更多互联网精彩资讯、工作效率提升关注【飞鱼在浪屿】(日更新)

shell脚本基础命令(Xargs使用指南-你所需要知道的Shell语言)(1)


什么是xargs?

它是数组和文本流之间的一个argv适配器。它指定如何拆分stdin,然后它生成参数并调用进程。示例:

$ echo 'alice bob' | xargs -n 1 -- echo hi hi alice hi bob

解释下发生了什么?

  1. xargs拆分输入流,产生 2 个参数, alice和bob.
  2. 我们通过了-n 1,xargs然后将每个参数传递给一个单独的echo hi $ARG命令。默认情况下,它会将尽可能多的参数传递给命令,例如echo hi alice bob.

在逻辑上xargs用“ each”这个词代替可能更有意义。如在,对于每个单词、行或标记,使用这些 args 调用此进程

我应该知道哪些命令选项?
  1. 文本拆分为参数 (如 -d, -0)的算法
  2. 有多少参数传递给每个进程( -n)。这决定了启动的进程总数
  3. 进程是按顺序运行还是并行运行 ( -P)

在继续讲xargs之前,或许你会问shell自带glob这些就够用了吗

Glob 可能就足够了

比如替代xargs

rm $(ls | grep foo)

还可以用shell 内置的 glob:

rm *foo*


更喜欢xargs Shell 的分词

这个建议很糟糕,因为命令依赖于shell 的分词。未引用的$(). 最好使用xargs提供的拆分算法,因为它们更简单且功能更强大。

例如,如果想要正则表达式的强大功能来过滤名称,您可以通过管道传输到 egrep,然后通过换行显式拆分其输出:

# Remove Python and C unit tests ls | egrep '.*_test\.(py|cc)' | xargs -d $'\n' -- rm


使用技巧选择三种拆分方式之一stdin

建议使用这三种拆分方式:

  1. xargs(默认无选项):当想用没有空格的“单词”时。例如,从 string 生成两个 args 'alice bob'。
  2. xargs -d $'\n':当希望 args 为lines 时,如上egrep所示。(请注意,这$'\n'是换行符的bash语法。)
  3. xargs -0:当要处理不受信任的数据时加上“-0”。比如有人在文件名中添加换行符。

大部分脚本使用第二种风格,偶尔使用第三种风格。


xargs可以使用$0调用 Shell 函数

xargs -I {},控制每个参数在argv数组中的替换位置。

但更多时候我会用xargs和 $0

do_one() { # Rather than xargs -I {}, it's more flexible to # use a function with $1 echo "Do something with $1" cp --verbose "$1" /tmp } do_all() { # Call the do_one function for each item. # Also add -P to make it parallel cat tasks.txt | xargs -n 1 -d $'\n' -- $0 do_one } "$@" # dispatch on $0; or use 'runproc' in Oil

使用以下任一命令运行此脚本:

这很好地分解了问题:让它在一个项目上工作,然后找出在哪些项目上运行它。

换句话说:使用 Shell 语言,而不是像xargs -I {}. 这减少了语言的复杂性


使用echo前缀预览任务

在运行如下命令之前:

$ cat tasks.txt | xargs -n 1 -- $0 do_one

使用以下命令进行预览通常很有用、:

$ cat tasks.txt | xargs -n 1 -- echo $0 do_one demo.sh do_one filename demo.sh do_one with demo.sh do_one spaces.txt # Oops! We split the input the wrong way. # We wanted xargs -d $'\n'.


xargs -P自动并行化任务

在do_all上面的示例中,可以添加-P 8 到xargs调用中并行处理!例如,如果有 1000 个独立任务,xargs将使用 8 个 CPU 来尽快运行它们。

但是这不能用for循环来做到这一点 。


为什么要使用find | xargs而不是find -exec.

答案是它可以快得多。如果尝试处理 rm 10,000 个文件,则可以启动 一个 进程而不是 10,000 个进程!

基本上是下面两个的区别

rm one two three

rm one rm two rm three

也许你还会说使用find -exec 而不是find -exec \;,

链接:


xargs与其他工具组合

除了避免使用迷你语言之外,还find | xargs可以在管道中插入其他工具。也就是说,find -exec是“硬编码”的,而管道允许明扩展,例如:

# Filter tasks by name find ... | grep ... | xargs ... # Limit the number of tasks. I use this all the time # for faster testing find ... | head | xargs ... # Believe it or not, I use this to randomize music # and videos :) find ... | shuf | xargs mplayer

所以 shell 是一种比find更具组合性的语言。


回顾

重复一遍,以下是我提倡的风格的好处:

  1. 增量开发:弄清楚在每个项目上做什么(什么是任务?),然后弄清楚在什么项目上做(我应该运行什么任务?)
  2. 通过使用echo预览任务轻松测试。这可以避免在错误的输入上运行长时间的批处理作业!
  3. 更好的性能。xargs让您启动尽可能少的进程。它还允许您并行启动这些进程。你不能用 for 循环来做到这一点。
  4. 需要记住的语言更少。我们对xargs使用普通 shell 和一些标志 。
  5. 通过管道组合

结论:以 Shell 为中心的 Shell 编程

我们在各种工具中避免使用“其他语言”,而是使用 shell 语言:

,