使xargs处理包含空格的文件名

时间:2013-05-26 10:53:00

标签: shell find xargs

$ ls *mp3 | xargs mplayer  

Playing Lemon.  
File not found: 'Lemon'  
Playing Tree.mp3.  
File not found: 'Tree.mp3'  

Exiting... (End of file)  

我的命令失败,因为文件“Lemon Tree.mp3”包含空格,因此xargs认为它是两个文件。我可以让find + xargs使用这样的文件名吗?

11 个答案:

答案 0 :(得分:197)

xargs实用程序从标准输入中读取空格,制表符,换行符和文件结束分隔符,并以字符串作为参数执行实用程序。

您希望避免将空格用作分隔符。这可以通过更改xargs的分隔符来完成。根据手册:

 -0      Change xargs to expect NUL (``\0'') characters as separators,
         instead of spaces and newlines.  This is expected to be used in
         concert with the -print0 function in find(1).

如:

 find . -name "*.mp3" -print0 | xargs -0 mplayer

回答关于播放第七个mp3的问题;它更简单的运行

 mplayer "$(ls *.mp3 | sed -n 7p)"

答案 1 :(得分:188)

-d命令将空格字符(制表符,空格,换行符)作为分隔符。您可以仅使用ls *.mp3 | xargs -d '\n' mplayer 选项对新行字符(' \ n')缩小范围,如下所示:

-0

它仅适用于GNU xargs。对于BSD系统,请使用ls *.mp3 | xargs -0 mplayer 选项,如下所示:

<tr><td width="30%" align="center"><p><input type="submit" id="btnSubmit" class="btn btn-primary" value="Upload" /></p></td></tr>
<tr><td valign="middle" align="center">         
<div id="load" style="display:none;"><img src="@Url.Content("~/Content/Images/loading.gif")" class="img-responsive" width="40" height="40" alt=""></div> 
</td></tr>

此方法更简单,也适用于GNU xargs。

答案 2 :(得分:24)

尝试

find . -name \*.mp3 -print0 | xargs -0 mplayer

而不是

ls | grep mp3 

答案 3 :(得分:9)

MacOS上的xargs没有-d选项,因此该解决方案使用-0代替。

获取ls每行输出一个文件,然后将换行符转换为空值并告诉xargs使用空值作为分隔符:

ls -1 *mp3 | tr "\n" "\0" | xargs -0 mplayer

答案 4 :(得分:5)

find . -name 'Lemon*.mp3' -print0 | xargs -­0 -i mplayer '{}' 

这有助于我删除带空格的不同文件。它应该与mplayer一起工作。必要的技巧是引号。 (在Linux Xubuntu 14.04上测试。)

答案 5 :(得分:5)

Dick.Guertin的回答[1]建议可以逃避文件名中的空格是这里建议的其他解决方案的有价值的替代方法(例如使用空字符作为分隔符而不是空格)。但它可能更简单 - 你真的不需要一个独特的角色。您可以直接添加转义空格:

ls | grep ' ' | sed 's| |\\ |g' | xargs ...

此外,仅当 希望名称中包含空格的文件时,才需要grep。更一般地说(例如,当处理一批文件时,其中一些文件有空格,有些没有空格),只需跳过grep:

ls | sed 's| |\\ |g' | xargs ...

然后,当然,文件名可能有空白而不是空格(例如,标签):

ls | sed -r 's|[[:blank:]]|\\\1|g' | xargs ...

假设你有一个支持-r(扩展正则表达式)的sed,例如GNU sed或bsd sed的最新版本(例如,FreeBSD最初在FreeBSD 8之前拼写选项“-E”并支持-r&amp; -E至少通过FreeBSD 11实现兼容性。否则,您可以使用基本的正则表达式字符类括号表达式,并在[]分隔符中手动输入空格和制表符。

[1]这可能更适合作为对该答案的评论或编辑,但目前我没有足够的声誉来评论,只能建议编辑。由于后面的形式(没有grep)改变了Dick.Guertin的原始答案的行为,因此直接编辑可能不合适。

答案 6 :(得分:4)

ls | grep mp3 | sed -n "7p" | xargs -i mplayer {}

请注意,在上面的命令中,xargs会为每个文件重新调用mplayer。对mplayer这可能不合适,但对其他目标可能没问题。

答案 7 :(得分:2)

这取决于(a)你是如何依附于7号而不是柠檬,以及(b)你的任何文件名是否包含换行符(以及你是否愿意重新命名它们他们这样做。)

有很多方法可以解决它,但其中一些是:

mplayer Lemon*.mp3

find . -name 'Lemon*.mp3' -exec mplayer {} ';'

i=0
for mp3 in *.mp3
do
    i=$((i+1))
    [ $i = 7 ] && mplayer "$mp3"
done

for mp3 in *.mp3
do
    case "$mp3" in
    (Lemon*) mplayer "$mp3";;
    esac
done

i=0
find . -name *.mp3 |
while read mp3
do
    i=$((i+1))
    [ $i = 7 ] && mplayer "$mp3"
done

如果文件名包含换行符,则read循环不起作用;即使名称中有换行符,其他人也能正常工作(更不用说空格了)。对于我的钱,如果你有包含换行符的文件名,你应该重命名没有换行符的文件。在文件名周围使用双引号是循环正常工作的关键。

如果您有GNU find和GNU xargs(或FreeBSD(* BSD?)或Mac OS X),您还可以使用-print0-0选项,如:

find . -name 'Lemon*.mp3' -print0 | xargs -0 mplayer

无论名称的内容如何,​​这都有效(文件名中只能出现的两个字符是斜线和NUL,斜杠在文件路径中没有问题,因此使用NUL作为名称分隔符可以覆盖所有内容) 。但是,如果您需要过滤掉前6个条目,则需要一个处理&#39;行的程序。以NUL而不是换行结束......我不确定是否有。

第一个是迄今为止最简单的具体案例;但是,它可能不会概括为涵盖您尚未列出的其他情景。

答案 8 :(得分:2)

在macOS 10.12.x(Sierra)上,如果文件名或子目录中有空格,则可以使用以下内容:

find . -name '*.swift' -exec echo '"{}"' \; |xargs wc -l

答案 9 :(得分:1)

鉴于这篇文章的具体标题,我的建议如下:

ls | grep ' ' | tr ' ' '<' | sed 's|<|\\ |g'

我们的想法是将空格转换为任何唯一字符,例如&#39;&lt;&#;;然后将其更改为&#39; \&#39;,反斜杠后跟空格。然后,您可以将其传递到您喜欢的任何命令中,例如:

ls | grep ' ' | tr ' ' '<' | sed 's|<|\\ |g' | xargs -L1 GetFileInfo

这里的关键在于&#39; tr&#39;并且&#39; sed&#39;命令;并且您可以使用&#39;&lt;&#;;之类的任何字符,例如&#39;?&#39;甚至是制表符。

答案 10 :(得分:0)

替代解决方案可能会有所帮助......

您还可以使用Perl在行尾添加空字符,然后使用xargs中的-0选项。与xargs -d'\ n'(在批准的答案中)不同 - 这适用于任何地方,包括OS X。

例如,以递归方式列出(执行,移动等)可能包含空格或其他有趣字符的JPEG图像 - 我会使用:

find . | grep \.jpg | perl -ne 'chop; print "$_\0"' | xargs -0  ls

(注意:对于过滤,我更喜欢更容易记住的“| grep”语法来“查找”--name参数。)