shell脚本基础命令(Xargs使用指南-你所需要知道的Shell语言)
更多互联网精彩资讯、工作效率提升关注【飞鱼在浪屿】(日更新)
什么是xargs?
它是数组和文本流之间的一个argv适配器。它指定如何拆分stdin,然后它生成参数并调用进程。示例:
$ echo 'alice bob' | xargs -n 1 -- echo hi
hi alice
hi bob
解释下发生了什么?
- xargs拆分输入流,产生 2 个参数, alice和bob.
- 我们通过了-n 1,xargs然后将每个参数传递给一个单独的echo hi $ARG命令。默认情况下,它会将尽可能多的参数传递给命令,例如echo hi alice bob.
在逻辑上xargs用“ each”这个词代替可能更有意义。如在,对于每个单词、行或标记,使用这些 args 调用此进程。
我应该知道哪些命令选项?- 将文本拆分为参数 (如 -d, -0)的算法
- 有多少参数传递给每个进程( -n)。这决定了启动的进程总数
- 进程是按顺序运行还是并行运行 ( -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
建议只使用这三种拆分方式:
- xargs(默认无选项):当想用没有空格的“单词”时。例如,从 string 生成两个 args 'alice bob'。
- xargs -d $'\n':当希望 args 为lines 时,如上egrep所示。(请注意,这$'\n'是换行符的bash语法。)
- 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
使用以下任一命令运行此脚本:
- demo.sh do_one $ARG对每个项目所做的工作。
- demo.sh do_all对所有项目进行处理。
这很好地分解了问题:让它在一个项目上工作,然后找出在哪些项目上运行它。
换句话说:使用 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 \;,
链接:
- 显示find -exec 速度较慢的比较 :https : //www.reddit.com/r/ProgrammingLanguages/comments/frhplj/some_syntax_ideas_for_a_shell_please_provide/fm07izj/
- 另一个比较:https://old.reddit.com/r/commandline/comments/45xxv1/why_find_stat_is_much_slower_than_ls/
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更具组合性的语言。
回顾
重复一遍,以下是我提倡的风格的好处:
- 增量开发:弄清楚在每个项目上做什么(什么是任务?),然后弄清楚在什么项目上做(我应该运行什么任务?)
- 通过使用echo预览任务轻松测试。这可以避免在错误的输入上运行长时间的批处理作业!
- 更好的性能。xargs让您启动尽可能少的进程。它还允许您并行启动这些进程。你不能用 for 循环来做到这一点。
- 需要记住的语言更少。我们对xargs使用普通 shell 和一些标志 。
- 通过管道组合。
结论:以 Shell 为中心的 Shell 编程
我们在各种工具中避免使用“其他语言”,而是使用 shell 语言:
- Shell 函数 and $1, 而不是xargs -I {}
- xargs而xargs -n 1不是find -exec 和find -exec \;
- -n而不是-L(为了避免临时数据语言)
- 带有简单标志的xargs而不是 GNU 并行
- Bash 语法$'\n'而不是工具语法'\n'。使用 shell 比依赖每个工具来理解 2 字符转义序列更简单\n。
免责声明:本文仅代表文章作者的个人观点,与本站无关。其原创性、真实性以及文中陈述文字和内容未经本站证实,对本文以及其中全部或者部分内容文字的真实性、完整性和原创性本站不作任何保证或承诺,请读者仅作参考,并自行核实相关内容。文章投诉邮箱:anhduc.ph@yahoo.com