我编写了以下脚本,在 Windows 7 下的 Git Bash 下运行:
#!/usr/bin/env sh
for logfile in `find -name "*.log" -o -name "*.err" -o -name "*.out"`
do
echo $logfile
grep "api/" "$logfile"
done
问题是,当文件名中有空格时,grep 会卡住。我以为双引号应该可以解决这个问题,但它却不配合。
有想法吗?
答案1
解决方案 1
最接近的解决方案是使用find
并-print0
读取输出while read …
:
find -name "*.log" -o -name "*.err" -o -name "*.out" -type f -print0 | while IFS= read -r -d '' logfile; do
...
继续使用"$logfile"
引号,就像使用变量时一样。
解决方案 2
另一个解决方案是find
根本不使用,而只是让其grep
在多个文件上运行:
shopt -s nullglob
shopt -s globstar
grep "api/" **/*.log **/*.err **/*.out
这里,globstar
启用目录的递归匹配**
。您应该设置nullglob
以防止在其中一个文件扩展名不存在时出现错误。
但这仅适用于有限的文件集,因为您可能会达到命令行参数的最大长度。
为什么会发生错误?
你永远不应该在(或,或任何其他输出带空格的文件名的函数)for
的输出上运行。阅读find
ls
本文了解有关为什么这是个问题以及如何解决它的更多信息。
简而言之,Bash 使用空格来分割参数。假设您有三个文件,a
、foo bar
和b
,那么该行将计算为:
for logfile in a foo bar b; do
显然,Bash 会设置logfile
为a
、foo
、bar
和b
,这不是您想要的。如果您可以手动将输入指定为for
,则可以将这些文件名括在引号中以解决问题。
为了自动执行此操作,解决方案是用字符分隔这些文件名NUL
(这是选项所做的-print0
),然后再次根据该字符拆分输出NUL
(这是-d ''
inread
所做的)。