Skip to content

Commit 8e038c2

Browse files
committed
docs: add xargs
1 parent 09e8aa0 commit 8e038c2

File tree

1 file changed

+245
-0
lines changed

1 file changed

+245
-0
lines changed

docs/xargs.md

+245
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,245 @@
1+
# xargs 命令
2+
3+
## 简介
4+
5+
xargs 用于将标准输入(stdin),转成其后命令的字符串参数。它通常跟管道命令(`|`)结合使用。
6+
7+
```bash
8+
$ {{command1}} | xargs {{command2}}
9+
```
10+
11+
上面是 xargs 的用法。正常情况下,第一个命令`command1`会输出结果到控制台(即标准输出`stdout`),但是管道命令(`|`)会拦截`command1`的标准输出,将其转为后面命令的标准输入(`stdin`),即`xargs`命令会接收到标准输入,它再将其转为`command2`的字符串参数来运行。
12+
13+
举例来说,文本文件`list.txt`的内容是一组文件名。
14+
15+
```bash
16+
a.txt
17+
b.txt
18+
c.txt
19+
```
20+
21+
然后,执行下面的命令,会将这组文件全部删除。
22+
23+
```bash
24+
# 删除 a.txt b.txt c.txt
25+
$ cat list.txt | xargs rm
26+
```
27+
28+
上面示例中,`cat`命令将`list.txt`的内容输出到标准输出,但是被管道命令拦截,转为`xargs`的标准输入,后者再将标准输入转成`rm`命令的字符串参数,即实际执行的是下面的命令。
29+
30+
```bash
31+
$ rm a.txt b.txt c.txt
32+
```
33+
34+
通常来说,Linux 命令分成两种,一种接受标准输入(一般是键盘)作为参数,另一种接受命令行的字符串作为参数。这两种参数的性质有很大的不同:标准输入(stdin)是文本流(stream),理论上只要不终止,就是无限的;命令行参数则是一个有固定长度的文本数组。xargs 的 作用就是接受标准输入,将其转成命令行参数。
35+
36+
xargs 有点像 echo 命令的逆操作。echo 命令是将命令行参数转为标准输出。
37+
38+
```bash
39+
$ echo abc
40+
```
41+
42+
上面命令中,`abc`是命令行参数,`echo`命令将其转为标准输入。
43+
44+
至于管道命令`|`,则是将前一个命令的标准输出,转成后一个命令的标准输入。但是,大多数命令只接受命令行参数,所以管道命令就需要 跟 xargs 结合使用,这是 Linux 的常见操作。
45+
46+
## xargs 的单独使用
47+
48+
xargs 命令也可以单独使用,这时等同于执行`xargs echo`
49+
50+
```bash
51+
$ xargs
52+
# 等同于
53+
$ xargs echo
54+
```
55+
56+
输入`xargs`后按下回车,命令行就会等待标准输入(即用户的键盘输入)。你可以输入任意内容,然后按下 Ctrl+d,表示输入结束,这时`echo`命令就会把前面的输入打印出来。
57+
58+
```bash
59+
$ xargs
60+
hello (Ctrl + d)
61+
hello
62+
```
63+
64+
上面示例中,执行`xargs`后,从键盘输入`hello`,然后按下 Ctrl+d,就会自动执行`echo hello`
65+
66+
再看一个例子。
67+
68+
```bash
69+
$ xargs find -name
70+
"*.txt"
71+
./foo.txt
72+
./hello.txt
73+
```
74+
75+
上面示例中,输入`xargs find -name`以后,命令行会等待用户输入所要搜索的文件。用户输入`"*.txt"`,表示搜索当前目录下的所有 TXT 文件,然后按下 Ctrl+d,表示输入结束,这时就相当执行`find -name *.txt`
76+
77+
## -d 参数与分隔符
78+
79+
默认情况下,`xargs`将换行符和空格作为分隔符,把标准输入分解成一个个命令行参数。
80+
81+
```bash
82+
$ echo "one two three" | xargs mkdir
83+
```
84+
85+
上面代码中,`mkdir`会新建三个子目录,因为`xargs``one two three`分解成三个命令行参数,执行`mkdir one two three`
86+
87+
`-d`参数可以更改分隔符。
88+
89+
```bash
90+
$ echo -e "a\tb\tc" | xargs -d "\t" echo
91+
a b c
92+
```
93+
94+
上面的命令指定制表符`\t`作为分隔符,所以`a\tb\tc`就转换成了三个命令行参数。`echo`命令的`-e`参数表示解释转义字符。
95+
96+
## -p 参数,-t 参数
97+
98+
使用`xargs`命令以后,由于存在转换参数过程,有时需要确认一下到底执行的是什么命令。
99+
100+
`-p`参数打印出要执行的命令,询问用户是否要执行。
101+
102+
```bash
103+
$ echo 'one two three' | xargs -p touch
104+
touch one two three ?...
105+
```
106+
107+
上面的命令执行以后,会打印出最终要执行的命令,让用户确认。用户按下回车以后,才会真正执行。
108+
109+
`-t`参数则是打印出最终要执行的命令,然后直接执行,不需要用户确认。
110+
111+
```bash
112+
$ echo 'one two three' | xargs -t rm
113+
rm one two three
114+
```
115+
116+
## -0 参数与 find 命令
117+
118+
由于`xargs`默认将空格作为分隔符,所以不太适合处理文件名,因为文件名可能包含空格。
119+
120+
`find`命令有一个特别的参数`-print0`,指定输出的文件列表以`null`分隔。然后,`xargs`命令的`-0`参数表示用`null`当作分隔符。
121+
122+
```bash
123+
$ find /path -type f -print0 | xargs -0 rm
124+
```
125+
126+
上面命令删除`/path`路径下的所有文件。由于分隔符是`null`,所以处理包含空格的文件名,也不会报错。
127+
128+
还有一个原因,使得`xargs`特别适合`find`命令。有些命令(比如`rm`)一旦参数过多会报错“参数列表过长”,而无法执行,改用`xargs`就没有这个问题,因为它对每个参数执行一次命令。
129+
130+
```bash
131+
$ find . -name "*.txt" | xargs grep "abc"
132+
```
133+
134+
上面命令找出所有 TXT 文件以后,对每个文件搜索一次是否包含字符串`abc`
135+
136+
## -L 参数
137+
138+
如果标准输入包含多行,`-L`参数指定多少行作为一个命令行参数。
139+
140+
```bash
141+
$ xargs find -name
142+
"*.txt"
143+
"*.md"
144+
find: paths must precede expression: `*.md'
145+
```
146+
147+
上面命令同时将`"*.txt"`和`*.md`两行作为命令行参数,传给`find`命令导致报错。
148+
149+
使用`-L`参数,指定每行作为一个命令行参数,就不会报错。
150+
151+
```bash
152+
$ xargs -L 1 find -name
153+
"*.txt"
154+
./foo.txt
155+
./hello.txt
156+
"*.md"
157+
./README.md
158+
```
159+
160+
上面命令指定了每一行(`-L 1`)作为命令行参数,分别运行一次命令(`find -name`)。
161+
162+
下面是另一个例子。
163+
164+
```bash
165+
$ echo -e "a\nb\nc" | xargs -L 1 echo
166+
a
167+
b
168+
c
169+
```
170+
171+
上面代码指定每行运行一次`echo`命令,所以`echo`命令执行了三次,输出了三行。
172+
173+
## -n 参数
174+
175+
`-L`参数虽然解决了多行的问题,但是有时用户会在同一行输入多项。
176+
177+
```bash
178+
$ xargs find -name
179+
"*.txt" "*.md"
180+
find: paths must precede expression: `*.md'
181+
```
182+
183+
上面的命令将同一行的两项作为命令行参数,导致报错。
184+
185+
`-n`参数指定每次将多少项,作为命令行参数。
186+
187+
```bash
188+
$ xargs -n 1 find -name
189+
```
190+
191+
上面命令指定将每一项(`-n 1`)标准输入作为命令行参数,分别执行一次命令(`find -name`)。
192+
193+
下面是另一个例子。
194+
195+
```bash
196+
$ echo {0..9} | xargs -n 2 echo
197+
0 1
198+
2 3
199+
4 5
200+
6 7
201+
8 9
202+
```
203+
204+
上面命令指定,每两个参数运行一次`echo`命令。所以,10个阿拉伯数字运行了五次`echo`命令,输出了五行。
205+
206+
## -I 参数
207+
208+
如果`xargs`要将命令行参数传给多个命令,可以使用`-I`参数。
209+
210+
`-I`指定每一项命令行参数的替代字符串。
211+
212+
```bash
213+
$ cat foo.txt
214+
one
215+
two
216+
three
217+
218+
$ cat foo.txt | xargs -I file sh -c 'echo file; mkdir file'
219+
one
220+
two
221+
three
222+
223+
$ ls
224+
one two three
225+
```
226+
227+
上面代码中,`foo.txt`是一个三行的文本文件。我们希望对每一项命令行参数,执行两个命令(`echo``mkdir`),使用`-I file`表示`file`是命令行参数的替代字符串。执行命令时,具体的参数会替代掉`echo file; mkdir file`里面的两个`file`
228+
229+
## --max-procs 参数
230+
231+
`xargs`默认只用一个进程执行命令。如果命令要执行多次,必须等上一次执行完,才能执行下一次。
232+
233+
`--max-procs`参数指定同时用多少个进程并行执行命令。`--max-procs 2`表示同时最多使用两个进程,`--max-procs 0`表示不限制进程数。
234+
235+
```bash
236+
$ docker ps -q | xargs -n 1 --max-procs 0 docker kill
237+
```
238+
239+
上面命令表示,同时关闭尽可能多的 Docker 容器,这样运行速度会快很多。
240+
241+
## 参考链接
242+
243+
- [xargs is the inverse function of echo](https://dhashe.com/xargs-is-the-inverse-function-of-echo.html)
244+
- [Linux and Unix xargs command tutorial with examples](https://shapeshed.com/unix-xargs/), George Ornbo
245+
- [8 Practical Examples of Linux Xargs Command for Beginners](https://www.howtoforge.com/tutorial/linux-xargs-command/), Himanshu Arora

0 commit comments

Comments
 (0)