如何转义 grep 的输出以便 bash 可以正确读取文件名?
我有一个文本文件,它是 find 命令的输出。对于每一行,我想创建一个符号链接。现在,我只是用 测试我的循环ls
。但是,我没有为特殊字符正确引用 grep 的字符串输出。这会导致每个文件上的文件系统命令失败。
$ tree dir/
dir/
├── Another & file ' name.txt
└── file name.txt
0 directories, 2 files
$ cat files.txt
dir
dir/Another & file ' name.txt
dir/file name.txt
$ grep file files.txt | awk -v q='"' '{printf(q"%s"q"\n", $0);}'
"dir/Another & file ' name.txt"
"dir/file name.txt"
$ while read p ; do
echo $p; ls $(grep file files.txt | awk -v q='"' '{printf(q"%s"q"\n", $0);}') ;
done < files.txt
dir
ls: cannot access '"dir/Another': No such file or directory
ls: cannot access '&': No such file or directory
ls: cannot access 'file': No such file or directory
...
dir/Another & file ' name.txt
ls: cannot access '"dir/Another': No such file or directory
ls: cannot access '&': No such file or directory
ls: cannot access 'file': No such file or directory
...
我已经尝试过单引号和双引号。如何转义它以在 grep 输出的路径上执行命令?
答案1
在
ls $(grep file file.txt)
您错误地使用了 split+glob 运算符,这就是您的问题所在。您不想在 的输出中插入引号,grep
因为该输出不会被解释为 shell 代码(谢天谢地!),但您需要调整 split+glob 运算符。
这里
您不需要 glob 部分(
*
例如将单词扩展为当前目录中的文件列表),因此您需要通过以下方式禁用它:set -o noglob
grep
您只想分割换行符的输出(这仍然意味着您的文件名不能包含换行符,但这是对file.txt
文件格式的限制):IFS=' '
或者
IFS=$'\n'
在一些贝壳中。
然后你可以调用 split+glob 运算符(不加$(...)
引号),但更像是:
ls -d -- $(grep file files.txt)
split+glob 运算符是从 Bourne shell 继承的一个缺陷。对于现代 shell,还有其他方法可以将某些文本拆分为其行列表。
使用 zsh:
ls -d -- ${(f)"$(grep file files.txt)"}
参数f
扩展标志是在换行符上分割(行Fps:\n:'
eed), (s:string:
用于分割任意字符串,p
以理解该字符串中的转义序列)的缩写\n
。我们引用$(...)
禁用 split+glob 运算符,尽管在 的情况下zsh
,只有分裂部分(无全局)。
和bash
:
readarray -t files < <(grep file files.txt)
ls -d -- "${files[@]}"
xargs
当使用as的输入格式是一个空白分隔列表时,您可能想要插入引号,xargs
其中分隔符可以用单引号、双引号或反斜杠引用(但与 shell 引用的方式不同)。
所以你可以这样做:
sed '
s/"/"\\""/; # escape the " characters themselves
s/^/"/;s/$/"/; # insert one at the beginning and one at the end
' < files.txt | xargs ls -d --