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

it_*_*ure 232 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)  
Run Code Online (Sandbox Code Playgroud)

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

Ray*_*Ray 219

xargs命令将空格字符(制表符,空格,换行符)作为分隔符.您可以使用以下-d选项将其缩小到仅适用于新行字符('\n'):

ls *.mp3 | xargs -d '\n' mplayer
Run Code Online (Sandbox Code Playgroud)

它仅适用于GNU xargs.对于BSD系统,请使用如下-0选项:

ls *.mp3 | xargs -0 mplayer
Run Code Online (Sandbox Code Playgroud)

这种方法更简单,也适用于GNU xargs.

  • 不幸的是,OS X上没有此选项. (25认同)
  • 在OS X上,-E'\n'对我没有影响,我也没想到它会修改eofstr而不是记录分隔符.但是,通过在我的输入中模拟find的-print0标志的效果,我能够利用-0标志作为解决方案,即使前一个命令不是'find',例如:ls*mp3 | tr'\n''\ 0'| xargs -0 mplayer (25认同)
  • @Thomas对于OS X,标志是`-E`,例如:`xargs -E'\n'` (23认同)
  • 对于OS X,您可以"brew install findutils",它为您提供**具有-d开关的"gxargs"命令. (8认同)
  • 一般用途的最佳答案!即使您以前的命令不是"查找",这也可以工作 (5认同)
  • gxargs 获胜 (2认同)
  • [在 scipts 中使用 `ls` 是一个坏主意。](https://mywiki.wooledge.org/ParsingLs) 这种特定情况的正确解决方法是简单地使用 `mplayer *.mp3` 而不是尝试使用 `xargs` 。 (2认同)

Jen*_*ens 206

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).
Run Code Online (Sandbox Code Playgroud)

如:

 find . -name "*.mp3" -print0 | xargs -0 mplayer
Run Code Online (Sandbox Code Playgroud)

回答关于播放每七个mp3的问题; 它运行起来比较简单

 mplayer "$(ls *.mp3 | sed -n 7p)"
Run Code Online (Sandbox Code Playgroud)

  • 这是使用GNU`find`和GNU`xargs`; 并非所有这些程序的版本都支持这些选项(尽管有一个案例可以提供). (10认同)
  • 而Mac OS X(一个BSD衍生产品)使用`-print0`````和`-0`使用`xargs`.但是,AFAIK,HP-UX,AIX和Solaris都没有(但我有待纠正:HP-UX 11i没有; Solaris 10没有; AIX 5.x没有;但它们不是最新版本).例如,使用''\ 0'`而不是''\n'`结尾的'lines'和POSIX 2008 [`getdelim()`](http)来改变`sed`并不难. ://pubs.opengroup.org/onlinepubs/9699919799/functions/getdelim.html)可以让您轻松管理. (5认同)
  • 使用包含列表文件的文件路径的+1 + 1技巧:cat $ file_paths_list_file | perl -ne's | \n |\000 | g; print'| xargs -0 zip $ zip_package (2认同)
  • 用NUL替换换行符的好主意-我必须在没有GNU查找,GNU xargs或perl的嵌入式系统上执行此操作-但是可以利用tr命令执行相同的操作:cat $ file_paths_list_file | tr'\ n''\ 0'| xargs -0 du -hms (2认同)

Sco*_*son 25

尝试

find . -name \*.mp3 -print0 | xargs -0 mplayer
Run Code Online (Sandbox Code Playgroud)

代替

ls | grep mp3 
Run Code Online (Sandbox Code Playgroud)


Gra*_*yle 12

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

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

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


shr*_*use 9

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

给定以下文件系统:

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

0 directories, 4 files
Run Code Online (Sandbox Code Playgroud)

find 命令可以用来处理 Dream Theater 和 King's X 中的空间。因此,使用 grep 查找每个乐队的鼓手:

[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
Run Code Online (Sandbox Code Playgroud)

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

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

所以,find bands/ -type f -exec grep Drums {} +会导致:

grep Drums "bands/Dream Theater" "bands/Rush" "bands/King's X" "bands/Megadeth"
Run Code Online (Sandbox Code Playgroud)

并将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"
Run Code Online (Sandbox Code Playgroud)

在这种情况下,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
Run Code Online (Sandbox Code Playgroud)

当然,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
Run Code Online (Sandbox Code Playgroud)

看到该-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
Run Code Online (Sandbox Code Playgroud)

xargs可以更好地控制命令行上可以有多少文件。为该-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]# 
Run Code Online (Sandbox Code Playgroud)

请注意,这grep是使用两个文件名执行的,因为-l2.


Jua*_*uan 7

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

ls | grep ' ' | sed 's| |\\ |g' | xargs ...
Run Code Online (Sandbox Code Playgroud)

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

ls | sed 's| |\\ |g' | xargs ...
Run Code Online (Sandbox Code Playgroud)

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

ls | sed -r 's|[[:blank:]]|\\\1|g' | xargs ...
Run Code Online (Sandbox Code Playgroud)

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

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


小智 5

find . -name 'Lemon*.mp3' -print0 | xargs -­0 -i mplayer '{}' 
Run Code Online (Sandbox Code Playgroud)

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


小智 5

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

find . -name '*.swift' -exec echo '"{}"' \; |xargs wc -l
Run Code Online (Sandbox Code Playgroud)