誰能一步一步解釋一下 bash 行中發生了什麼?我是新來的,試圖了解這段程式碼是如何運作的,特別是來自echo
:
read char; echo -e "YES\nNO\n" | grep -i $char
答案1
char
該行的命令可能以交互方式從使用者讀取字串到變數中。
echo
+管道grep
嘗試確定輸入的字串是否為肯定字串。它透過將單字YES
和NO
與輸入的字串(以輸入的字串作為模式)進行匹配來實現此目的,不區分大小寫。如果使用者輸入單字中存在的大寫或小寫字元或子字串YES
,結果將是YES
;如果他們輸入字串中存在的大寫或小寫字元或子字串NO
,則結果將為NO
。輸入類似的內容maybe
將導致空輸出。
這種方法的缺點是,例如,如果使用者輸入 ,.
和YES
都會NO
匹配,因為grep
會將點視為與任何字元匹配的正規表示式。由於$char
在對 的呼叫中未加引號grep
,因此如果使用者輸入 shell 通配模式(例如 input),它也有可能導致對機器的拒絕服務攻擊/*/*/*/*/../../../../*/*/*/*
(範例取自忘記在 bash/POSIX shell 中引用變數的安全隱患)。您也可能透過輸入eg -r -o -e . /
(將每個非二進位檔案的每個字元單獨輸出一行,前面加上該檔案所屬檔案的路徑名)來導致命令的輸出混亂。
您顯示的代碼“奇怪且不尋常”,因為它使用用戶輸入本質上是程式碼,即它使用用戶輸入作為圖案,並測試靜態數據針對這種可變模式。這與通常所做的相反,通常的做法是獲取使用者的輸入並根據靜態模式測試此可變資料。
更常見的是使用類似以下的程式碼:
read -p 'Yes/[N]o: ' yesno
if [[ $yesno == [Yy]* ]]; then
# code for affirmative
else
# code for non-affirmative
fi
上面的程式碼從用戶讀取一個字串並測試它是否以 ay
或Y
字元開頭。如果是,則將採用該語句的第一個分支if
,但否則將預設採用該else
分支。
顯然,您還可以測試整個單詞YES
,或者[Yy][Ee][Ss]
不區分大小寫的匹配,或者通過驗證進行正確的輸入循環:
while true; do
read -p 'Yes/No: ' yesno
if [ "$yesno" = Yes ] || [ "$yesno" = No ]; then
break
fi
echo 'Please enter "Yes" or "No"' >&2
done
# $yesno is either Yes or No here
(或類似的東西)。
請注意上面的兩個範例程式碼如何僅將使用者的輸入用作資料而不是模式。
將您的原始命令至少重寫為一些慣用的命令(但功能不同,並且可能並非萬無一失),會將其變成
read yesno; printf '%s\n' "${yesno^^}" | grep -i -w -E 'yes|no'
如果使用者輸入or ,這將傳回大寫字母YES
或。這在功能上是不同的,因為它要求用戶輸入的內容不僅僅是a等。NO
yes
no
e
yes
答案2
好吧,讓我們依次執行每個命令:
read char
這將從標準輸入(通常是您的鍵盤,但可能是間接檔案或管道流;請參閱下文)讀取,並將接收到的資料放入名為 的變數中char
。
echo -e "YES\nNO\n"
echo
將向標準輸出(通常是終端)顯示提供的參數。此-e
開關(通常但並非總是如此;echo
在一致性實作方面存在一些問題)可讓您e
轉義某些字元以進行一些基本的格式化。在本例中,它使用的是 using \n
,它是轉義的n
,它是 ewline 的簡寫n
。
grep -i $char
grep
是一個搜尋提供的輸入以查看是否有與提供的模式相符的工具。這個-i
開關告訴它是i
不區分大小寫的搜尋。
和|
命令之間是一個「管道」。這將第一個命令的輸出連接到第二個命令的輸入,這意味著將在該語料庫中搜尋變數內容中反映的模式:echo
grep
grep
char
YES
NO
此命令序列的實際結果是查看提供的輸入(根據變數名稱假設為單個字符,但未檢查這一點)。如果該字元是Y
、E
、S
、y
、e
或s
,則輸出將為YES
。如果該字元是N
、O
、n
、 或o
,則輸出將為NO
。但是,如果(例如)輸入是yo
or ne
,則不會輸出任何內容。
如前所述,不檢查輸入是一個字元的假設。這不是給定範例命令序列中唯一的反模式。例如,變數沒有被引用;並且正在使用正規表示式工具 ( grep
),而無需對輸入進行正規表示式通配符篩選。
答案3
從 中讀取“字元”(而不是:字串)/dev/stdin
。意思是:你輸入它。
然後兩行輸出到/dev/stdout
.意思是你的控制台。
然後透過管道(“|”)將其 grep 為不區分大小寫的輸入版本。
這意味著如果您輸入“bar”,它將簡單地完成而沒有任何明顯的輸出,但如果您輸入“y”,那麼它將輸出行“YES”,甚至很可能會突出顯示“Y”