简体   繁体   English

bash shell 循环脚本

[英]bash shell script for loop

I have a bash shell script that loops through a server list file to verify a user exists on that server.我有一个 bash shell 脚本循环遍历服务器列表文件以验证用户是否存在于该服务器上。 My question is, I want the script to echo out which servers the user exists on before executing command: sleep;我的问题是,我希望脚本在执行命令之前回显用户所在的服务器:sleep; clear;清除; main_sec <(this is a function) problem is as soon as that condition is met, it just echo's the first server met then executes code. main_sec <(this is a function) 问题是只要满足该条件,它就会回显第一个遇到的服务器然后执行代码。 How do i echo it all out then execute the code?我如何将其全部回显然后执行代码?

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

What you want is to save a match and use it later.您想要的是保存匹配并在以后使用它。 You can use a variable for that:您可以为此使用变量:

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

Here is a corrected version of your code with all my advice from below:这是您的代码的更正版本,其中包含以下我的所有建议:

#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

Some code mistakes you can avoid:您可以避免的一些代码错误:

Don't assume $?不要假设$? won't change!不会改变!

Your second execution of $?你第二次执行$? will be 0 as it's if 's return code (unless you change your code) Instead of the syntax command; if [ $? ]将是0 ,因为它是if的返回码(除非你改变你的代码)而不是语法command; if [ $? ] command; if [ $? ] command; if [ $? ] , use: command; if [ $? ] ,使用:

if ssh ...; then
  ...
else
  ...
fi

https://mywiki.wooledge.org/BashPitfalls#pf44 https://mywiki.wooledge.org/BashPitfalls#pf44

Avoid [避免[

[ or test is the POSIX test command. [test是 POSIX 测试命令。 It can do simple tests on files and strings.它可以对文件和字符串进行简单的测试。 In bash, you should use the more powerful [[ instead and ban [ for sake of consistency.在 bash 中,您应该使用更强大的[[代替并禁止[以保持一致性。 [[ can do pattern matching, is faster and safer to use. [[可以做模式匹配,使用起来更快更安全。

http://mywiki.wooledge.org/BashGuide/TestsAndConditionals http://mywiki.wooledge.org/BashGuide/TestsAndConditionals

http://mywiki.wooledge.org/BashFAQ/031 http://mywiki.wooledge.org/BashFAQ/031

Termination终止

main_sec will launch something else, and you don't want lines further down the script continue executing once you finish so you should add an exit afterwards to be sure you really terminate when main_sec finishes main_sec将启动其他内容,并且您不希望脚本在完成后继续执行,因此您应该在之后添加一个退出以确保您在main_sec完成时真正终止

egrep is deprecated egrep已弃用

Use grep -E if needed (not needed here)如果需要,请使用grep -E (此处不需要)

Don't do grep... > /dev/null不要做grep... > /dev/null

If you only want the return code, use grep -q .如果您只想要返回码,请使用grep -q This avoid scanning all the input when you only want to know if a match is there.当您只想知道是否存在匹配时,这可以避免扫描所有输入。 It helps for larger inputs.它有助于更大的输入。

Consider using getent instead of /etc/passwd考虑使用getent而不是 /etc/passwd

Instead of scanning /etc/passwd, you should use getent which is designed for it It also covers domain accounts, if it helps.而不是扫描 /etc/passwd,你应该使用为它设计的getent它还包括域帐户,如果它有帮助的话。

Capital variable names大写变量名

By convention, we capitalize environment variables ( PAGER , EDITOR , ..) and internal shell variables ( SHELL , BASH_VERSION , ..).按照惯例,我们将环境变量( PAGEREDITOR 、..)和内部 shell 变量( SHELLBASH_VERSION 、..)大写。 All other variable names should be lower case.所有其他变量名称应为小写。 Remember that variable names are case-sensitive;请记住,变量名是区分大小写的; this convention avoids accidentally overriding environmental and internal variables.此约定避免意外覆盖环境和内部变量。

Don't use echo with options flags不要将echo与选项标志一起使用

echo outputs a string. echo输出一个字符串。 echo has many portability problems, and should never be used with option flags. echo有很多可移植性问题,不应该与选项标志一起使用。 Consider printf instead: printf 'name: %s\n' "$name" .考虑printf代替: printf 'name: %s\n' "$name"

http://wiki.bash-hackers.org/commands/builtin/echo http://wiki.bash-hackers.org/commands/builtin/echo

http://cfajohnson.com/shell/cus-faq.html#Q0b http://cfajohnson.com/shell/cus-faq.html#Q0b

http://www.in-ulm.de/~mascheck/various/echo+printf http://www.in-ulm.de/~mascheck/various/echo+printf

In this case, you are using echo -e '$RED... $NONE' .在这种情况下,您使用的是echo -e '$RED... $NONE'

I'm guessing it's because RED='\e[31m' NONE='\e(B\e[0m'我猜这是因为RED='\e[31m' NONE='\e(B\e[0m'

If you used these values instead, you could use the colors without echo 's -e :如果您改用这些值,则可以使用 colors 而不使用echo-e

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

Don't assume variables will not contain special characters不要假设变量不会包含特殊字符

Here, username may be set by someone who has ill intent to values such as ; rm -rf /在这里, username可能由对值有恶意的人设置,例如; rm -rf / ; rm -rf / . ; rm -rf / Once launched on you ssh servers, this could be disastrous.一旦在 ssh 服务器上启动,这可能是灾难性的。 Even if you have set the username in the code yourself, you don't know if the code won't be changed in the future to some form of user-defined value, so you should protect your code against this while you still can by escaping special characters before passing them to ssh .即使您自己在代码中设置了用户名,您也不知道将来代码是否不会更改为某种形式的用户定义值,因此您应该保护您的代码免受这种情况的影响,同时您仍然可以通过escaping 特殊字符,然后将它们传递给ssh There are many ways to do that, and one is:有很多方法可以做到这一点,其中一种是:

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