grep 转义文件名结果

grep 转义文件名结果

如何转义 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 运算符。

这里

  1. 您不需要 glob 部分(*例如将单词扩展为当前目录中的文件列表),因此您需要通过以下方式禁用它:

    set -o noglob
    
  2. 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 --

相关内容