我正在尝试使用 .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
答案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
使用-print0
and-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
采用第一个参数。