[英]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.