【问题标题】:For loop reading word instead of lines in bash [duplicate]For循环读取单词而不是bash中的行[重复]
【发布时间】:2019-10-28 09:39:54
【问题描述】:

我遇到了一个明显简单的脚本的问题。

基本上是这样的:

for s in $(cat FILENAME| grep User)
do
echo "$s"

done

但不是给我类似的结果:

User bla bla bla
User2 something blabla

结果是:

User
bla
bla
bla
User2

【问题讨论】:

  • 如果您阅读 bash 手册,for x in ... 会循环遍历 单词,而不是行。这对这项工作来说是错误的工具。
  • @GordonDavisson:不一定。空格通常是一个问题,如果您遍历文件或查找结果,您可能会遇到空格。如果在所有这些情况下都不能使用“for”,那就太糟糕了。这就是 IFS 派上用场的地方(见下文)。
  • @jottbe 同样在这些情况下,for 是错误的工具。
  • 您要求正确的方法来编写 shell 循环以读取 grep 的输出,然后准确输出 grep 在没有循环的情况下将输出的内容。不要这样做,原因很明显,它毫无意义,而且你可能根本不应该使用这种方法来做你真正想做的事情。如果您正在考虑这样做,您应该阅读unix.stackexchange.com/q/169716/133219 和几个常见问题解答。还要谷歌 UUOC!

标签: bash grep


【解决方案1】:

正如@donjuedo 所说,空格通常被视为分隔符,这就是为什么你没有得到整行的原因。有几种方法可以解决这个问题。 我列出了从文件和命令输出中读取的解决方案。作为输入,您可以创建一个包含以下内容的文件并将其命名为 testfile.txt(空行、行间和两端都有空格:

This is the first line
2
third line

fifth line 
 sixth line   

解决方案 1:最普遍适用

while IFS= read -u 3 -r line; do
    echo ">${line}<"
    read -p "press enter to show next line" var
    echo "read caught the following input: >$var<"
done 3< testfile.txt

从管道读取的变体看起来完全一样,只是最后一行发生了变化。作为一个例子,我处理了测试文件中包含空格的所有行,这消除了第二行和第四行(这里用

while IFS= read -r line <&3;  do
   ...
done 3< <(grep " " testfile.txt)

这适用于大型输入文件。 3

  • 也适用于大型输入文件而不会占用内存

  • stdin 未重定向(使用 fd 3)

  • 谎言之间和两端的空格被保留(使用 IFS)

  • 空行保留得很好

感谢@BenjaminW 提出这个建议。

解决方案 2:使用 IFS 和 for(有限制)

OFS="$IFS"
IFS=$'\n'
for line in $(cat testfile.txt) ; do
  echo ">${line}<"
  read -p "press enter to show next line" var
  echo "read caught the following input: >$var<"
done
IFS="$OFS"

这会暂时将字段分隔符更改为换行符,因此文件仅在换行符处拆分。

  • 不推荐用于大型输入,因为命令行替换 ($(cat testfile))

  • stdin 也没有被重定向,因此可以在 body 中使用 stdin 而没有限制

  • 谎言之间和两端的空格被保留(使用 IFS)

  • 此处跳过作为第 4 行的空行(第 0 行/匹配 ^$)

  • 如果你使用它,你必须确保你重置了 IFS

  • 如果您的循环体需要对字段进行不同的解释(例如,需要读取应该在空格周围分割的其他内容),它可能会变得混乱。

【讨论】:

  • 感谢它的工作:cat apm | grep 用户| while read ligne do echo "$ligne" done
  • 这取决于路径名扩展;你可以用set -f 压制它。它还跳过空行;见Why you don't read lines with "for"。所以,总而言之,最好还是改用while IFS= read -r line; do ... done &lt; &lt;(grep ... infile) 之类的东西。
  • 我会使用 read -r -u3 line; do ...; read var; ...; done 3&lt; &lt;(grep ... infile) 来做到这一点。
  • 您必须在while 行上添加-u3 以使while 从该文件描述符中读取。
【解决方案2】:

catgrep 正在生成行,其中恰好包含空格。 for 构造是从每一块而不是每一行中生成 $s。

根据您所展示的,您可以简单地使用catgrep,而不必为循环而烦恼。

【讨论】:

    猜你喜欢
    • 2010-12-11
    • 2019-04-09
    • 2013-10-04
    • 2021-03-02
    • 1970-01-01
    • 1970-01-01
    • 2015-08-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多