簡體   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