2015-04-05 217 views
1

我試圖grep行匹配某種模式,然後嘗試打印這些匹配的行。Bash腳本:從文件打印grep'd行

#!/bin/bash 

file=/path/to/some/file 
pattern=socket 
if [ -f $file ]; then 
    lines=`grep -i "$pattern" $file` 
# Case 1 
    for x in $lines; do # <--- isn't this an array 
     echo "$x"                                                                 
     done 
# Case 2 
    while read -r line_a; do 
     echo "$line_a" 
     done <<< "$lines" 
fi 

輸出:
情況1:代替完整線,從這些行各個字印在每個新行。
案例2:單行打印。

問:
爲什麼不區分1個打印整條生產線在同一行,而不是從該行對每個新行打印個人的話嗎?是不是$lines字符串數組(在我的情況下)?

+1

沒有它不是一個數組,通過使用反引號將'grep'的結果捕獲爲一個大字符串。我猜測for循環將空白視爲記錄分隔符,因此每個單詞都被視爲一個元素 – Pankrates 2015-04-05 01:45:53

回答

0

您目前正在使用back ticks捕獲輸出,它將整個輸出視爲一個大字符串。如果你想捕捉到它作爲一個數組使用下面的符號

lines=($(grep -i "$pattern" $file)) 

不過,默認的記錄分隔符是空格,讓每個數組元素將是一個字,而不是從grep輸出整條生產線。您可以通過(暫時)更改記錄分隔符IFS來分隔新行字符來避開此問題。整個解決方案會是什麼樣子,你現在已經改變IFS爲外殼下面

IFS=$'\n' 
lines=($(grep -i "$pattern" $file)) 
for x in ${lines[@]}; do 
    echo $x 
done 

注意,你可能會想將其重置爲舊值。正如你所看到的,這種方法很可能不是最適合你的問題,但我在這裏發佈它來回答你原來的問題

+0

'lines =($(grep -i「$ pattern」$ file))'....它仍然沒有工作。它將以空格分隔的字符存儲爲數組的元素。 – brokenfoot 2015-04-05 02:18:54

+1

你是否將'IFS'設置爲換行符? – Pankrates 2015-04-05 03:00:53

+0

是的,這是問題所在。謝謝! – brokenfoot 2015-04-05 03:28:53

2

不是$行的字符串數組(在我的情況下是行)?

否; $lines是一個標量字符串變量,包含從命令grep -i "$pattern" $file捕獲的整個輸出整個輸出 - 換句話說:包含潛在多行的單個字符串。

爲什麼第一種情況不是在一行上打印整行而不是在每一行上打印該行中的單個單詞?

因爲你參考變量$lines未加引號,這意味着它是受分詞(除其他所謂shell expansions)。

文字分割意味着輸入被空白(甚至跨越線條)分成標記,每個標記分別傳遞到for循環。


通過單一輸入字符串,即使你設置$IFS到$ '\n',還有就是遍歷與for線沒有安全的方式,因爲該行仍受到路徑擴展(通配符);即,如果一行包含恰好是有效全局符號的子串(文件名模式,例如,,*),它將被擴展爲匹配的文件名。

使用的線的陣列一個for迴路的工作,但要求它與未修飾的輸入線來填充;出於與上述相同的原因,使用lines=($(grep -i "$pattern" "$file"))來填充陣列不是一種選擇。


你有兩個選擇,它們都使用一個process substitution捕捉grep命令的輸出:

(a)如果你真的需要預先讀取所有行入內存,強勁閱讀成排列如下:

IFS=$'\n' read -d '' -ra lines < <(grep -i "$pattern" "$file") 

在bash 4+,您可以使用readarray -t lines ...來代替。

然後處理它們在for循環如下:

for line in "${lines[@]}"; do # double quotes prevent word splitting and globbing 
    echo "$line" 
done 

(b)否則,使用while環直接讀取由線grep的輸出線:

while IFS= read -r line; do 
    echo "$line" 
done < <(grep -i "$pattern" "$file") 
+0

感謝您的詳細解釋。我最近開始研究bash,我可以在哪裏瞭解何時使用 - 單引號,雙引號,後蜱,大括號,方括號,圓括號等。 – brokenfoot 2015-04-05 03:49:18

+0

http://stackoverflow.com/a/23140961/45375會給你一個快速介紹引用; [shell擴展](https://www.gnu.org/software/bash/manual/html_node/Shell-Expansions.html)討論了shell執行的所有擴展(替換)。 http://mywiki.wooledge.org/BashGuide是一個很棒的Bash資源。另外,不要忘記'男人bash',其中包含所有相關信息,但密集,不容易閱讀。 – mklement0 2015-04-05 03:59:49

+0

你能解釋一下(b),IFS的價值是什麼?我能夠單獨閱讀這些行,但在這些行中,字符「n」的任何外觀都被替換爲「」(空格)。 – brokenfoot 2015-04-07 19:30:21