Bash:如何从命令的输出中一次读取一行?

Bash:如何从命令的输出中一次读取一行?

我正在尝试使用 .bashrc 文件读取 bash 中命令的输出while loop

while read -r line
do
    echo "$line"
done <<< $(find . -type f)

我得到的输出

ranveer@ranveer:~/tmp$ bash test.sh
./test.py ./test1.py ./out1 ./test.sh ./out ./out2 ./hello
ranveer@ranveer:~/tmp$ 

之后我尝试过

$(find . -type f) | 
while read -r line
do
    echo "$line"
done 

但它产生了一个错误test.sh: line 5: ./test.py: Permission denied

那么,我如何逐行阅读它,因为我认为目前它正在一次性读取整行。

所需输出:

./test.py
./test1.py
./out1
./test.sh
./out
./out2
./hello

答案1

有一个错误,你< <(command)不需要<<<$(command)

< <( )是一个流程替代$()命令替换并且<<<是一个这里的字符串

答案2

如果您想使用管道,则无需命令替换。默认情况read下读取stdin,因此您只需通过管道输入即可:

find . -type f -print0 |
while read -r -d '' line
do
    echo "$line"
done

或在一行中

find . -type f -print0 | while read -r -d '' line; do echo "$line"; done

使用-print0and-d ''是针对文件名中潜在换行符的保护措施,默认情况下表示行尾为read(可以使用 进行更改-d)。''上面使用的实际上是空字节bash(相当于$'\0')。

另一种已经提到的方法是使用find's-exec选项。这很可能是性能方面的最佳选择(记住使用-exec cmd {} +变体,这样它就不会为正在处理的每一行分叉一个进程)。但这实际上取决于您在while循环内执行的操作以及处理的数据量。对于您的情况来说,差异可能可以忽略不计或可以接受。

答案3

请注意,没有什么可以阻止文件名包含换行符。为每个文件运行命令的规范方法成立通过查找是。

find . -type f -exec cmd {} \;

如果你想在 bash 中完成事情:

find . -type f -exec bash -c '
  for file do
    something with "$file"
  done' bash {} +

另外,在脚本中调用“read”命令的规范方法(如果您不希望它对输入进行额外的处理)是:

IFS= read -r var

-r是停止read特殊处理反斜杠字符(作为分隔符和换行符的转义字符),并且 IFS= 将分隔符列表设置为空字符串read(否则,如果该列表中存在任何空白字符,它们将从输入的开始和结束)。

在 shell 中使用循环通常是一个坏主意(不是在 shell 中完成任务的方式,在 shell 中,您可以让多个工具共同并同时执行一项任务,而不是按顺序运行一个或多个工具数百次)。

答案4

一个小的修改斯特凡·查泽拉斯的回答

find . -type f -exec bash -c 'echo $0; head $0;' {} \;

这显示了您提供的脚本如何bash -c采用第一个参数。

相关内容