如何循环 STDIN 中的行并运行 shell 命令?

如何循环 STDIN 中的行并运行 shell 命令?

我想在从 STDIN 获取的每一行上运行 shell 命令。

在这种情况下,我想跑步xargs mv。例如,给定两行:

mfoo foo
mbar bar

我想运行:

xargs mv mfoo foo
xargs mv mbar bar

我已经尝试了以下策略rubyawk、 和xargs。然而,我做错了:

只是xargs

$ echo "mbar bar\nmbaz baz" | xargs mv
usage: mv [-f | -i | -n] [-v] source target
       mv [-f | -i | -n] [-v] source ... directory

通过awk

$ echo "mbar bar\nmbaz baz" | awk '{ system("xargs $0") }'

通过ruby

$ echo "mbar bar\nmbaz baz" | ruby -ne '`xargs mv`'
$ ls
cat  foo  mbar mbaz

我有一些疑问:

  • 我该如何做我想做的事?
  • 我的每一次尝试都出了什么问题?
  • 有没有更好的方法来“思考”我正在尝试做的事情?

我特别困惑的是我的xargs尝试不起作用,因为以下方法有效:

$ echo "foo\nbar" | xargs touch
$ ls
bar foo

答案1

echo "mbar bar\nmbaz baz" | xargs mv

xargs应该使用该-t选项来看看发生了什么。因此,在上面的情况下,如果我们要调用xargswith -t,我们会看到什么:

mv mbar bar mbaz baz

所以显然这是不正确的。发生的事情是,xargs就像一条饥饿的鳄鱼,吃掉了通过管道喂给它的所有参数echo。所以你需要一种方法来限制向 croc 释放参数。由于您是按行请求的,因此您需要的是-l-Lfor POSIX 选项。

echo "mbar bar\nmbaz baz" | xargs -l -t mv

POSIX 方式:

echo "mbar bar\nmbaz baz" | xargs -L 1 -t mv

mv mbar bar
mv mbaz baz

这就是你想要的。华泰

答案2

你可以这样走:

echo -e "foo bar\ndoo dar" | xargs -n 2 mv

从文件中读取:

cat lines.txt | xargs -n 2 mv

或者

xargs -a lines.txt -n 2 mv

答案3

xargs可能不会按照您的预期行事。请参阅@MichaelHomer对此问题的评论:

xargs mv mfoo foo将等待输入并为它获得的mfoo foo $x_1 $x_2 $x_3...每一行输入运行 mv 。 $x_n@迈克尔霍默

这可以通过阅读来确认xargs手册页

描述
xargs 实用程序从标准输入读取空格、制表符、换行符和文件结尾分隔的字符串,并使用这些字符串作为参数执行实用程序。

xargs在实践中,当将参数提供给作为第一个参数给出的命令行实用程序时,似乎会忽略换行符。例如,请注意换行符会发生什么:

$ echo "foo bar\ncat dog"
foo bar
cat dog
$ echo "foo bar\ncat dog" | xargs echo
foo bar cat dog

这种行为可以通过以下方式控制-n旗帜

-n 数字


设置每次调用实用程序时从标准输入获取的参数的最大数量。

回到前面的例子,如果我们只想xargs使用 2 个参数然后退出,那么我们可以使用@ddnomad 的方法

$ echo "foo bar\ncat dog" | xargs -n 2 echo
foo bar
cat dog

另外,如 Rakesh Sharma 的答案中的评论所示,在 BSD 上,xargs您可以使用标志指定要读取的行数-L。从手册页:

-L号

为每个读取的数轴调用实用程序。如果达到 EOF 并且
读取的行数少于数量,则将使用可用行调用实用程序。

对于测试同样有帮助的是-t开关:

重新审视我们的示例,以下两种方法都可以工作;然而,第二个例子更好,因为这正是本例的目的:

$ echo "foo bar\ncat dog" | xargs -n 2 echo
foo bar
cat dog
$ echo "foo bar\ncat dog" | xargs -L 1 echo
foo bar
cat dog

手册页中的注释:

-L 和 -n 选项是互斥的;将使用最后给出的一个。

答案4

有一个非常简单的解决方案,不使用 xargs。
定义这个函数:

$ mv2() { while (($# >1 )); do echo mv "$1" "$2"; shift 2; done; }

然后,只需使用所需的文件名列表来调用它(不需要换行符):

$ mv2 mbar bar mbaz baz
mv mbar bar
mv mbaz baz

去掉回声,使功能真正发挥作用。

相关内容