Bash脚本:从文件打印grep'd行

问题描述:

我试图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

您目前正在使用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

不是$行的字符串数组(在我的情况下是行)?

否; $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://*.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