繁体   English   中英

bash shell 循环脚本

[英]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它还包括域帐户,如果它有帮助的话。

大写变量名

按照惯例,我们将环境变量( PAGEREDITOR 、..)和内部 shell 变量( SHELLBASH_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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM