了解 bash 命令列中的 read、echo 和 grep 命令

了解 bash 命令列中的 read、echo 和 grep 命令

誰能一步一步解釋一下 bash 行中發生了什麼?我是新來的,試圖了解這段程式碼是如何運作的,特別是來自echo

read char; echo -e "YES\nNO\n" | grep -i $char

答案1

char該行的命令可能以交互方式從使用者讀取字串到變數中。

echo+管道grep嘗試確定輸入的字串是否為肯定字串。它透過將單字YESNO與輸入的字串(以輸入的字串作為模式)進行匹配來實現此目的,不區分大小寫。如果使用者輸入單字中存在的大寫或小寫字元或子字串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

上面的程式碼從用戶讀取一個字串並測試它是否以 ayY字元開頭。如果是,則將採用該語句的第一個分支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等。NOyesnoeyes

答案2

好吧,讓我們依次執行每個命令:

read char

這將從標準輸入(通常是您的鍵盤,但可能是間接檔案或管道流;請參閱下文)讀取,並將接收到的資料放入名為 的變數中char

echo -e "YES\nNO\n"

echo將向標準輸出(通常是終端)顯示提供的參數。此-e開關(通常但並非總是如此;echo在一致性實作方面存在一些問題)可讓您e轉義某些字元以進行一些基本的格式化。在本例中,它使用的是 using \n,它是轉義的n,它是 ewline 的簡寫n

grep -i $char

grep是一個搜尋提供的輸入以查看是否有與提供的模式相符的工具。這個-i開關告訴它是i不區分大小寫的搜尋。

|命令之間是一個「管道」。這將第一個命令的輸出連接到第二個命令的輸入,這意味著將在該語料庫中搜尋變數內容中反映的模式:echogrepgrepchar

YES
NO

此命令序列的實際結果是查看提供的輸入(根據變數名稱假設為單個字符,但未檢查這一點)。如果該字元是YESyes,則輸出將為YES。如果該字元是NOn、 或o,則輸出將為NO。但是,如果(例如)輸入是yoor ne,則不會輸出任何內容。

如前所述,不檢查輸入是一個字元的假設。這不是給定範例命令序列中唯一的反模式。例如,變數沒有被引用;並且正在使用正規表示式工具 ( grep),而無需對輸入進行正規表示式通配符篩選。

答案3

從 中讀取“字元”(而不是:字串)/dev/stdin。意思是:你輸入它。

然後兩行輸出到/dev/stdout.意思是你的控制台。

然後透過管道(“|”)將其 grep 為不區分大小寫的輸入版本。

這意味著如果您輸入“bar”,它將簡單地完成而沒有任何明顯的輸出,但如果您輸入“y”,那麼它將輸出行“YES”,甚至很可能會突出顯示“Y”

相關內容