下面是一个简单的bash命令行:
grep -li 'regex' "filename with spaces" "filename"
没问题。 另外,以下的作品就好了:
grep -li 'regex' $(<listOfFiles.txt)
其中listOfFiles.txt
包含文件名列表被grepped,每行一个文件名。
出现问题时listOfFiles.txt
包含嵌入空格的文件名。 在我试过(见下文),所有的情况下,击分裂的空间,以便文件名,例如,在一行listOfFiles.txt
包含类似名称./this is a file.xml
最终试图在每次运行的grep件( ./this
, is
, a
和file.xml
)。
我想我是一个比较先进的Bash用户,但我无法找到一个简单的魔法咒语,得到这个工作。 下面是我试过的东西。
grep -li 'regex' `cat listOfFiles.txt`
失败如上所述(我真的不希望这个工作),所以我想我会把周围的每个文件名中的报价:
grep -li 'regex' `sed -e 's/.*/"&"/' listOfFiles.txt`
Bash解释引号作为文件名的一部分,并给出了每个文件“没有这样的文件或目录”( 现在仍然分裂的文件名用空格)
for i in $(<listOfFiles.txt); do grep -li 'regex' "$i"; done
这未按原始的尝试(也就是说,它的行为就好像引号被忽略),是非常缓慢的,因为它必须每个文件启动一个“grep”可以替代过程在处理一个调用的所有文件。
下面的工作,但需要注意一些双转义如果正则表达式包含shell元字符:
eval grep -li 'regex' `sed -e 's/.*/"&"/' listOfFiles.txt`
这是建立在命令行所以它会正确处理的文件名与空间的唯一途径?
试试这个:
(IFS=$'\n'; grep -li 'regex' $(<listOfFiles.txt))
IFS
是内部字段分隔符。 将其设置为$'\n'
告诉Bash使用换行符来分隔文件名。 它的默认值是$' \t\n'
,并且可以使用打印cat -etv <<<"$IFS"
。
括在括号中的脚本启动子shell,这样只有通过括号定制受影响范围内的命令IFS
值。
cat listOfFiles.txt |tr '\n' '\0' |xargs -0 grep -li 'regex'
在xargs的-0选项告诉xargs的使用空字符,而不是空白的文件名终止。 tr命令输入的换行符转换成一个空字符。
这符合一些grep不会被调用多次OP的要求。 这一直是我的经验,对于大量文件的grep避免的多次调用大大提高性能。
该方案也避免了错误的OP的原始方法,因为他的计划将打破地方listOfFiles.txt包含的数字将超过命令缓冲区大小的文件。 xargs的知道最大命令大小,将调用grep的多次来避免这个问题。
使用xargs的和grep一个相关的问题是,当有多个文件被调用的grep将前缀的文件名输出。 因为xargs的调用与多个文件的grep一个将收到前缀的文件名输出,但不适合在listOfFiles.txt一个文件或其中最后调用包含一个文件名多次调用的情况下的情况。 为了获得一致的输出添加/ dev / null来grep命令:
cat listOfFiles.txt |tr '\n' '\0' |xargs -0 grep -i 'regex' /dev/null
请注意,是不是为OP因为他用的grep上-l选项的问题; 但是,很可能成为别人的一个问题。
这工作:
while read file; do grep -li dtw "$file"; done < listOfFiles.txt
虽然它可能均优于,这是我最喜欢的解决方案:
grep -i 'regex' $(cat listOfFiles.txt | sed -e "s/ /?/g")
请注意,如果你以某种方式结束了其拥有的Windows行尾文件列表, \r\n
,票据概上述有关输入文件分隔符$IFS
(和报价参数)将工作; 所以请确保行结束正确\n
(我用scite
显示行尾,并轻松地将它们从一种模式改变为其他)。
此外cat
管道进入while file read ...
似乎工作(显然没有必要设置分隔符):
cat <(echo -e "AA AA\nBB BB") | while read file; do echo $file; done
...虽然对我来说是一个“grep的”通过文件名中使用空格的目录更相关:
grep -rlI 'search' "My Dir"/ | while read file; do echo $file; grep 'search\|else' "$ix"; done
与击4,也可以使用内置的映射文件函数来设置一个数组包含每一行,并重复这个阵列上:
$ tree
.
├── a
│ ├── a 1
│ └── a 2
├── b
│ ├── b 1
│ └── b 2
└── c
├── c 1
└── c 2
3 directories, 6 files
$ mapfile -t files < <(find -type f)
$ for file in "${files[@]}"; do
> echo "file: $file"
> done
file: ./a/a 2
file: ./a/a 1
file: ./b/b 2
file: ./b/b 1
file: ./c/c 2
file: ./c/c 1