|
| 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