xargs 将标准输入转成命令行参数
有些命令不支持输入流
前面我们讲过,有些命令是不支持输入流的,只支持命令行参数,如最常用的 ls
。我们通常这样使用
$ ls /var/
backups cache crash lib local lock log mail metrics opt run snap spool tmp
但是不能这样使用
$ echo "/var" | ls
这样使用的话,ls 会忽略管道传递给它的输入流。最终相当于,仅仅运行了不带参数的 ls。
xargs 的用处
那么,如果命令行或脚本确实需要用到类似的写法,有什么解决办法呢?答案就是用 xargs,xargs 的其中一个作用就是可以将管道或标准输入的数据转换成命令行参数,例如
$ echo "/var" | xargs ls
backups cache crash lib local lock log mail metrics opt run snap spool tmp
以上,加了一个 xargs ,就可以将管道的输出转换成 ls 的参数。
原理分析
管道本来的作用是连接 echo 的标准输出
到 ls 的标准输入
,加了 xargs,就相当于管道连接了 echo 的标准输出到 xargs 的标准输入,xargs 又将其标准输入的内容转换成命令的参数,传递给命令。
源码分析
先上源码
xargs.c
# define READ_ARGS(l, e, nmc, mc) process_stdin(l, e, nmc, mc)
int xargs_main(int argc, char **argv)
{
while ((list = READ_ARGS(list, eof_str, n_max_chars, max_chars)) != NULL || /* 从标准输入读取数据作为参数列表 */
(opt & OPT_NO_EMPTY) == 0)
{
opt |= OPT_NO_EMPTY;
n = 0;
n_chars = 0;
/* allocating pointers for execvp:
a*arg, n*arg from stdin, NULL */
args = xcalloc(n + a + 1, sizeof(char *));
/* Store the command to be executed
(taken from the command line) */
for (i = 0; i < a; i++)
args[i] = argv[i];
/* (taken from stdin) */
for (cur = list; n; cur = cur->link) {
args[i++] = cur->data;
n--;
}
if ((opt & OPT_INTERACTIVE) == 0 || xargs_ask_confirmation() != 0) {
child_error = xargs_exec(args); /* 执行命令,其中 args 的值可能为: args[0] = "ls", args[1] = "-a" */
}
/* clean up */
for (i = a; args[i]; i++) {
cur = list;
list = list->link;
free(cur);
}
free(args);
if (child_error > 0 && child_error != 123) {
break;
}
}
return child_error;
}
所以,xargs 的原理就是读取标准输入,转成参数列表,借助 exec 函数,执行命令和参数。
提升
我们发现,通过 xargs 执行的 ls 命令,失去了颜色,那是因为在 shell 中执行的 ls,实际上执行的是 ls --color=auto
,ls 是 alias 给 ls --color=auto
起的别名。要想我们的输出带颜色,可以使用如下命令:
呐,颜色回来了