Answers:
尝试结合使用find -print0
或-printf
option,xargs
如下所示:
find /music -iname "*\.mp3" -print0 | xargs -0 mpg321
-打印0
真正; 在标准输出上打印完整的文件名,后跟一个空字符(而不是-print使用的换行符)。这允许包含换行符或其他类型的空格的文件名可以由处理查找输出的程序正确解释。此选项对应于xargs的-0选项。
mpg321 $(find /music -iname "*\.mp3" -print0)
不呢?
mpg321
与它无关,它是将输入输出find
分解成单独参数的shell 。并且-print0 | xargs -0
可以使用所有可能的文件名。
find /music -iname "*\.mp3" -exec mpg123 {} +
使用GNU find,您还可以使用-print0
和xargs -0
,但是学习另一个工具毫无意义。该-exec ... {} +
语法变得很少提及因为Linux不迟于收购它-print0
,但没有理由现在不使用它。
使用zsh或bash 4,这要简单得多:
mpg123 **/*.[Mm][Pp]3
仅在zsh中,可以使模式(的一部分)不区分大小写:
mpg123 (#i)**/*.mp3
我认为Steven的解决方案是最好的,但是另一种方法是使用xargs的-I
标志,它使您可以指定一个字符串,然后在命令中将其替换为参数(而不是仅将参数附加到命令的末尾)。您可以使用它来引用参数:
find /music -iname "*\.mp3" | xargs -0 -Ifoo mpg321 "foo"
-0
标志,而没有find的标志-print0
。同样,xargs的-I
标志也有许多后果。不像普通的xargs
将所有行从stdin压缩为一个命令的普通文件,它xargs -I
可能执行mpg321
数百或数千次(每个文件一次),这肯定不是目的。还请记住,在xargs
内部也不需要引号foo 。请注意,如果您将所有文件名压缩到line行并将其发送到xargs -I
,它们将不会打开。
通常最好直接访问,-exec ${tgt_process} \{\} +
但是如果出于某种原因确实需要从文件或流中获取可靠分隔的文件名列表find
,则可以执行以下操作:
find -exec sh -c 'printf "///%s///\n" "$@"' -- \{\} +
您从中得到的是两个唯一的字符串。每个文件名的开头是字符串\n///
,每个文件名的末尾是字符串///\n
。find
不管文件名包含什么字符,这两个字符串都不会在输出中的其他任何位置出现,除了在那些位置。
此外,以上用法是POSIX便携式基准,可以在几乎所有的Unix系统上使用。尽管有人建议使用空字节定界符(尽管很方便),但事实并非如此。
但是,同样,这仅在-exec
您$tgt_process
出于任何原因而无法直接进行时才是必要的,因为那应该是您的目标。一方面,上述方法仍然需要解析。例如,如果您希望用引号将每个文件名shell括起来,则首先必须确保转义了文件名中的所有硬引号:
find ... + | sed 's|'\''|&"&"&|g;s|///|'\''|g'
这将输出一个正确的由外壳程序转义的文件名数组,无论它们的构成字符是什么。现在,您只希望希望接收端的应用程序不会损坏它。
另一种方法是转义文件名中的所有特殊字符。例如:
find /music -iname "*\.mp3" | sed 's!\([] \*\$\/&[]\)!\\\1!g' | xargs mpg321
基本上,这会将正确转义的文件名传递给xargs以便执行,不会有任何问题。
sed 's|.|\\&|g'
高兴-POSIX还是建议这么做。