我怎样才能让xargs处理包含空格的文件名?

$ ls *mp3 | xargs mplayer Playing Lemon. File not found: 'Lemon' Playing Tree.mp3. File not found: 'Tree.mp3' Exiting... (End of file) 

我的命令失败,因为文件“柠檬Tree.mp3”包含空格,所以xargs认为这是两个文件。 我可以使find + xargs像这样的文件名工作吗?

您可以使用-d选项将分隔字符更改为xargs的新行('\ n'):

 ls *mp3 | xargs -d '\n' mplayer 

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

你想避免使用空格作为分隔符。 这可以通过更改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 | grep mp3 | sed -n 7p)" 

尝试

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

代替

 ls | grep mp3 

Dick.Guertin的回答[1]表明,可以跳过文件名中的空格是对此处提出的其他解决scheme(例如使用空字符作为分隔符而不是空格)的有价值的替代scheme。 但它可能更简单 – 你并不需要一个独特的angular色。 你可以让sed直接添加转义空格:

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

此外,只有当你想要名称中有空格的文件时,grep才是必需的。 更一般地说(例如,当处理一批文件时,其中一些文件有空格,有些则没有),可以跳过grep:

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

那么,当然,文件名可能有空格而不是空格(例如,一个制表符):

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

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

[1]这可能更适合作为评论或编辑的答案,但目前我没有足够的声誉评论,只能build议编辑。 由于后者形成上面(没有grep)改变了Dick.Guertin的原始答案的行为,直接编辑也许是不适当的。

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

这有助于我的情况下删除不同的文件与空格。 它也应该与mplayer一起工作。 必要的技巧是行情。 (在linux xubuntu 14.04上的Testet)

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

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

这取决于(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 

不pipe名称的内容如何(只有两个不能出现在文件名中的字符是斜线和NUL,斜线在文件path中没有问题,所以使用NUL作为名称分隔符覆盖了所有内容)。 但是,如果你需要过滤掉前6个条目,你需要一个处理'NUL'而不是换行的'行'的程序,我不确定是否有。

第一个是目前最为简单的案例; 但是,它可能不能概括为涵盖你还没有列出的其他场景。

鉴于这篇文章的具体标题,这里是我的build议:

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

这个想法是将空格转换为任何独特的字符,比如“<”,然后将其转换为“\”,反斜杠后跟一个空格。 然后,您可以将其转换为您喜欢的任何命令,例如:

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

这里的关键在于“tr”和“sed”命令。 你可以使用除“<”之外的任何字符,比如“?” 甚至是制表符。

我知道我没有直接回答xargs问题,但值得一提的是find-exec选项。

鉴于以下文件系统:

 [root@localhost bokeh]# tree --charset assci bands bands |-- Dream\ Theater |-- King's\ X |-- Megadeth `-- Rush 0 directories, 4 files 

find命令可以处理Dream Theater和King's X的空间。所以,用grepfind每个band的鼓手:

 [root@localhost]# find bands/ -type f -exec grep Drums {} + bands/Dream Theater:Drums:Mike Mangini bands/Rush:Drums: Neil Peart bands/King's X:Drums:Jerry Gaskill bands/Megadeth:Drums:Dirk Verbeuren 

-exec选项中{}代表包含path的文件名。 请注意,您不必将其转义或放在引号中。

-exec的终结符( +\; )之间的区别在于+可以将多个文件名组合到一个命令行上。 而\; 将为每个文件名执行命令。

因此, find bands/ -type f -exec grep Drums {} +将导致:

 grep Drums "bands/Dream Theater" "bands/Rush" "bands/King's X" "bands/Megadeth" 

find bands/ -type f -exec grep Drums {} \; 将导致:

 grep Drums "bands/Dream Theater" grep Drums "bands/Rush" grep Drums "bands/King's X" grep Drums "bands/Megadeth" 

grep的情况下,这有副作用或打印文件名或不。

 [root@localhost bokeh]# find bands/ -type f -exec grep Drums {} \; Drums:Mike Mangini Drums: Neil Peart Drums:Jerry Gaskill Drums:Dirk Verbeuren [root@localhost bokeh]# find bands/ -type f -exec grep Drums {} + bands/Dream Theater:Drums:Mike Mangini bands/Rush:Drums: Neil Peart bands/King's X:Drums:Jerry Gaskill bands/Megadeth:Drums:Dirk Verbeuren 

当然, grep的选项-h-H将控制是否打印文件名,无论如何调用grep


xargs

xargs还可以控制man文件在命令行上的方式。

xargs默认将所有参数分组到一行上。 为了做同样的事情, -exec \; 使用xargs -l 。 请注意, -t选项告诉xargs在执行之前先打印命令。

 [root@localhost bokeh]# find ./bands -type f | xargs -d '\n' -l -t grep Drums grep Drums ./bands/Dream Theater Drums:Mike Mangini grep Drums ./bands/Rush Drums: Neil Peart grep Drums ./bands/King's X Drums:Jerry Gaskill grep Drums ./bands/Megadeth Drums:Dirk Verbeuren 

看到-l选项告诉xargs为每个文件名执行grep。

与默认(即没有-l选项):

 [root@localhost bokeh]# find ./bands -type f | xargs -d '\n' -t grep Drums grep Drums ./bands/Dream Theater ./bands/Rush ./bands/King's X ./bands/Megadeth ./bands/Dream Theater:Drums:Mike Mangini ./bands/Rush:Drums: Neil Peart ./bands/King's X:Drums:Jerry Gaskill ./bands/Megadeth:Drums:Dirk Verbeuren 

xargs可以更好地控制命令行中有多less个文件。 为-l选项提供每个命令的最大文件数量。

 [root@localhost bokeh]# find ./bands -type f | xargs -d '\n' -l2 -t grep Drums grep Drums ./bands/Dream Theater ./bands/Rush ./bands/Dream Theater:Drums:Mike Mangini ./bands/Rush:Drums: Neil Peart grep Drums ./bands/King's X ./bands/Megadeth ./bands/King's X:Drums:Jerry Gaskill ./bands/Megadeth:Drums:Dirk Verbeuren [root@localhost bokeh]# 

看到grep是由两个文件名执行的,因为-l2

这是一个旧的post,但替代解决scheme可以帮助…

您还可以使用Perl将空字符添加到行的末尾,然后在xargs中使用-0选项。 与xargs -d'\ n'(在批准的答案中)不同,这个方法无处不在,包括OSX。

例如,recursion列表(执行,移动等)的JPG图像,可能包含空格或其他有趣的人物 – 我会使用:

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

(注意:为了过滤,我更喜欢简单易记的“| grep”语法来“查找”–name参数。)