[英]bash shell script for loop
我有一个 bash shell 脚本循环遍历服务器列表文件以验证用户是否存在于该服务器上。 我的问题是,我希望脚本在执行命令之前回显用户所在的服务器:sleep; 清除; main_sec <(this is a function) 问题是只要满足该条件,它就会回显第一个遇到的服务器然后执行代码。 我如何将其全部回显然后执行代码?
echo -e "${YELLOW}Checking if user account exists on any of the servers above${NONE}"
readarray -t lines < servers.txt
for server in "${lines[@]}"; do
ssh -q -o StrictHostKeyChecking=no $server "egrep "^$username" /etc/passwd" &>/dev/null
if [ $? -eq 1 ]; then
continue
fi
if [ $? -eq 0 ]; then
echo -e "${RED}User account $username already exists on $server, Must choose a unique username before proceeding. Returning to menu...${NONE}"
sleep 5; clear; main_sec
fi
done
您想要的是保存匹配并在以后使用它。 您可以为此使用变量:
return_menu=
for ...; do
if ssh ...; then
...
else
echo >&2 "User account $username already exists on $server, Must choose a unique username before proceeding. Returning to menu..."
return_menu=return_menu
fi
fi
done
if [[ $return_menu != '' ]]; then
sleep 5
clear
main_sec
fi
这是您的代码的更正版本,其中包含以下我的所有建议:
#username=...
return_menu=
echo "${YELLOW}Checking if user account exists on any of the servers above$NONE"
readarray -t lines < servers.txt
for server in "${lines[@]}"; do
if printf 'getent passwd %q >/dev/null' "$username" |
ssh -q -o StrictHostKeyChecking=no "$server" bash -s; then
continue
else
printf >&2 '%s\n' \
"${RED}User account $username already exists on $server." \
"You must choose a unique username before proceeding." \
"${NONE}Returning to menu..."
return_menu=return_menu
fi
done
if [[ $return_menu != '' ]]; then
sleep 5
clear
main_sec
exit 0
fi
您可以避免的一些代码错误:
$?
不会改变! 你第二次执行$?
将是0
,因为它是if
的返回码(除非你改变你的代码)而不是语法command; if [ $? ]
command; if [ $? ]
command; if [ $? ]
,使用:
if ssh ...; then
...
else
...
fi
https://mywiki.wooledge.org/BashPitfalls#pf44
[
[
或test
是 POSIX 测试命令。 它可以对文件和字符串进行简单的测试。 在 bash 中,您应该使用更强大的[[
代替并禁止[
以保持一致性。 [[
可以做模式匹配,使用起来更快更安全。
http://mywiki.wooledge.org/BashGuide/TestsAndConditionals
http://mywiki.wooledge.org/BashFAQ/031
main_sec
将启动其他内容,并且您不希望脚本在完成后继续执行,因此您应该在之后添加一个退出以确保您在main_sec
完成时真正终止
egrep
已弃用如果需要,请使用grep -E
(此处不需要)
grep... > /dev/null
如果您只想要返回码,请使用grep -q
。 当您只想知道是否存在匹配时,这可以避免扫描所有输入。 它有助于更大的输入。
getent
而不是 /etc/passwd 而不是扫描 /etc/passwd,你应该使用为它设计的getent
它还包括域帐户,如果它有帮助的话。
按照惯例,我们将环境变量( PAGER
、 EDITOR
、..)和内部 shell 变量( SHELL
、 BASH_VERSION
、..)大写。 所有其他变量名称应为小写。 请记住,变量名是区分大小写的; 此约定避免意外覆盖环境和内部变量。
echo
与选项标志一起使用 echo
输出一个字符串。 echo
有很多可移植性问题,不应该与选项标志一起使用。 考虑printf
代替: printf 'name: %s\n' "$name"
。
http://wiki.bash-hackers.org/commands/builtin/echo
http://cfajohnson.com/shell/cus-faq.html#Q0b
http://www.in-ulm.de/~mascheck/various/echo+printf
在这种情况下,您使用的是echo -e '$RED... $NONE'
。
我猜这是因为RED='\e[31m' NONE='\e(B\e[0m'
如果您改用这些值,则可以使用 colors 而不使用echo
的-e
:
RED=$'\e[31m' NONE=$'\e(B\e[0m'
在这里, username
可能由对值有恶意的人设置,例如; rm -rf /
; rm -rf /
。 一旦在 ssh 服务器上启动,这可能是灾难性的。 即使您自己在代码中设置了用户名,您也不知道将来代码是否不会更改为某种形式的用户定义值,因此您应该保护您的代码免受这种情况的影响,同时您仍然可以通过escaping 特殊字符,然后将它们传递给ssh
。 有很多方法可以做到这一点,其中一种是:
printf 'getent passwd %q >/dev/null' "$username" | ssh -q -o StrictHostKeyChecking=no "$server" bash -s
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.