当我运行这个时:
for f in $(grep -r --include=*.directory "search-string"); do echo $f; done;
我得到的搜索结果按搜索结果文件名中的空格分开。
如何转义 grep 搜索结果中的空格?
答案1
如果您想要数组中的文件列表并使用 bash shell(版本 4.4 或更高版本),您可以这样做:
readarray -td '' files < <(
grep -rlZ --include='*.directory' "search-string" .
)
带壳zsh
:
files=(${(0)"$(grep -rlZ --include='*.directory' "search-string" .)"})
并用以下语句循环它们:
for file in "${files[@]}"; do
printf '%s\n' "$file"
done
使用zsh
,您可以通过以下方式跳过中间数组:
for file in ${(0)"$(grep -rlZ --include='*.directory' "search-string" .)"}; do
printf '%s\n' "$file"
}
请注意,不加引号的单词扩展(例如$f
或$(...)
)在 中具有非常特殊的含义bash
,通常不是您想要的,并且文件名可以包含除 之外的任何字节值0
,因此0
又名 NUL 是表达时可以安全使用的唯一分隔符文件路径列表作为带有分隔符的字节流。这就是GNU 的-Z
/选项的用途。--null
grep
使用诸如 之类的简单 shell dash
,您可以gawk
使用 GNU 的输出grep
来生成 shell 引用的文件名列表,以sh
作为 shell 代码进行计算:
eval set -- "$(
grep -rlZ --include='*.directory' "search-string" . |
gawk -v RS='\0' -v ORS=' ' -v q="'" '
{gsub(q, q "\\" q q); print q $0 q}'
)"
for file do
printf '%s\n' "$file"
done
如果您可以保证您的文件名不会包含换行符,您可以将其简化为:
IFS='
'
set -o noglob
for file in $(grep -rl --include='*.directory' "search-string" .); do
printf '%s\n' "$file"
done
set -o noglob
如果您可以保证文件名也不包含*
, ?
, [
(可能还有\
, 以及更多 glob 运算符,具体取决于 shell 和 shell 版本),则可以跳过 。
答案2
如果您确定文件路径中没有换行符,那么您可以将单词分割限制为换行符:
oldIFS="$IFS"
IFS=$'\n'
for f in $(grep -r --include=*.directory "search-string"); do
echo "$f"
done
IFS="$oldIFS"
答案3
grep
当 GNU 人员提供查找文件的选项时,他们真的搞砸了。希望他们不打算为 sed、awk、cat、tr、wc 和所有其他 UNIX 工具提供相同的功能,并希望他们不打算为 grep 选项提供现有工具执行的其他操作(例如排序文件),替换字符串、翻译字符、计算字符数等。有一个非常好的 UNIX 工具可以寻找文件,它有一个非常明显的名称 - find
.
while IFS= read -rd '' file; do
echo "$file"
done < <(find . -name '*.directory' -exec grep -lZ 'search-string' {} +)
上面需要 GNU 工具(您已经在使用)来使用 NUL 终止的输入/输出。如果您的文件名中没有换行符,那么您可以使用标准工具来代替。