bash shell脚本循环

问题描述 投票:-1回答:1

我有一个bash shell脚本,该脚本循环遍历服务器列表文件以验证该服务器上是否存在用户。我的问题是,我希望脚本在执行命令之前回显用户所在的服务器:明确; main_sec

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
linux bash
1个回答
0
投票

您想要保存一个匹配项,以后再使用。您可以为此使用变量:

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
fi

可以避免的一些代码错误:

不要假设$?不会改变!

您第二次执行的$?将为0,因为它是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,..)和内部外壳变量(SHELLBASH_VERSION,..)大写。所有其他变量名应小写。请记住,变量名称区分大小写;该约定避免了意外覆盖环境和内部变量。

不要将echo与选项标志一起使用

echo输出一个字符串。 echo具有许多可移植性问题,因此切勿与选项标志一起使用。考虑改为printfprintf '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'

如果改为使用这些值,则可以使用没有echo-e的颜色:

RED=$'\e[31m' NONE=$'\e(B\e[0m'

不要假设变量将不包含特殊字符

[此处,username可能由不希望使用; rm -rf /等值的人设置。在ssh服务器上启动后,这可能是灾难性的。即使您自己在代码中设置了用户名,您也不​​知道该代码将来是否会更改为某种形式的用户定义值,因此您应该保护代码免受此侵害,同时仍然可以在将特殊字符传递给ssh之前先进行转义。有很多方法可以做到这一点,其中一种是:

printf 'getent passwd %q >/dev/null' "$username" | ssh -q -o StrictHostKeyChecking=no "$server" bash -s
© www.soinside.com 2019 - 2024. All rights reserved.