如何在xargs -0之后执行多个命令?

时间:2011-09-19 14:58:55

标签: bash find xargs

find . -name "filename including space" -print0 | xargs -0 ls -aldF > log.txt
find . -name "filename including space" -print0 | xargs -0 rm -rdf

是否可以将这两个命令合并为一个,这样只能完成1个查找而不是2个?

我知道xargs -I可能有办法做到这一点,这可能会导致文件名(包括空格)时出错。非常感谢任何指导。

8 个答案:

答案 0 :(得分:48)

find . -name "filename including space" -print0 | 
  xargs -0 -I '{}' sh -c 'ls -aldF {} >> log.txt; rm -rdf {}'

答案 1 :(得分:16)

如果您只是想避免多次执行find,可以在tee之后立即执行find,将find输出保存到文件,然后执行以下行:

find . -name "filename including space" -print0 | tee my_teed_file | xargs -0 ls -aldF > log.txt
cat my_teed_file | xargs -0 rm -rdf 

完成同样事情的另一种方法(如果确实是你想要完成的事情)是将find的输出存储在一个变量中(假设它不是TB的数据):

founddata=`find . -name "filename including space" -print0`
echo "$founddata" | xargs -0 ls -aldF > log.txt
echo "$founddata" | xargs -0 rm -rdf

答案 2 :(得分:5)

我相信现在所有这些答案已经找到了解决这个问题的正确方法。我尝试了Jonathan的两个解决方案和Glenn的方式,所有这些解决方案在我的Mac OS X上运行良好.mouviciel的方法在我的操作系统上不起作用可能是由于一些配置原因。而且我认为它类似于乔纳森的第二种方法(我可能错了)。

正如对格伦方法的评论所述,需要进行一些调整。所以这是我试过的命令,完全合情合理:

find . -name "filename including space" -print0 | 
xargs -0 -I '{}' sh -c 'ls -aldF {} | tee -a log.txt ; rm -rdf {}'

或者格伦的建议更好:

find . -name "filename including space" -print0 | 
xargs -0 -I '{}' sh -c 'ls -aldF {} >> log.txt ; rm -rdf {}'

答案 3 :(得分:4)

只要您的文件名中没有换行符,就不需要-print0用于GNU Parallel:

find . -name "My brother's 12\" records" | parallel ls {}\; rm -rdf {} >log.txt

观看介绍视频以了解详情:http://www.youtube.com/watch?v=OpaiGYxkSuQ

答案 4 :(得分:2)

只是-print0方法的变体而没有可怕的xargs -0ls -1 *.txt | xargs --delimiter "\n" --max-args 1 --replace={} sh -c 'cat {}; echo "\n"' ,我就是这样做的:

xargs

脚注:

  • 是的,我知道新行可以出现在文件名中,但是谁能够做到这一点
  • ls -1有简短的选项,但为了读者的理解我已经使用了长的。{1}}。
  • 当我想要非递归行为时,我会使用find -maxdepth 1 -iname "*.txt",而不是style="width: 800px; table-layout: fixed" ,这会更加冗长。

答案 5 :(得分:1)

您可以使用find代替for xargs后执行多个命令:

IFS=$'\n'
for F in `find . -name "filename including space"`
do
    ls -aldF $F > log.txt
    rm -rdf $F
done

IFS定义内部字段分隔符,默认为< space>< tab>< newline>。如果您的文件名可能包含空格,最好按上述方式重新定义。

答案 6 :(得分:1)

我迟到了,但还有一个解决方案没有在这里讨论:用户定义的功能。在一行上放置多个指令是不实用的,并且可能难以阅读/维护。上面的for循环避免了这种情况,但是有可能超出命令行长度。

这是另一种方式(未经测试)。

function processFiles {
  ls -aldF "$@"
  rm -rdf "$@"
}
export -f processFiles

find . -name "filename including space"` -print0 \
  | xargs -0 bash -c processFiles dummyArg > log.txt

除了“dummyArg”给我带来很多悲伤之外,这是非常简单的。以这种方式运行bash时,参数被读入

"$0" "$1" "$2"  ....

而不是预期的

"$1" "$2" "$3"    ....

由于processFiles {}期望第一个参数为“ $ 1 ”,我们必须在“ $ 0”中插入一个虚拟值。

Footnontes:

  1. 我正在使用bash语法的一些元素(例如“ export -f ”),但我相信这会适应其他shell。
  2. 我第一次尝试这个时,没有添加伪参数。相反,我将“ $ 0 ”添加到我的函数内的参数行中(例如 ls -aldf“$ 0”“$ @”)。馊主意。 除了风格问题,当“查找”命令没有返回任何内容时,它会中断。在这种情况下,$ 0设置为“bash”,而使用伪参数则避免所有这些。

答案 7 :(得分:0)

另一种解决方案:

find . -name "filename including space" -print0 \
| xargs -0 -I FOUND echo "$(ls -aldF FOUND > log.txt ; rm -rdf FOUND)"