我想在从 STDIN 获取的每一行上运行 shell 命令。
在这种情况下,我想跑步xargs mv
。例如,给定两行:
mfoo foo
mbar bar
我想运行:
xargs mv mfoo foo
xargs mv mbar bar
我已经尝试了以下策略ruby
、awk
、 和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
选项来看看发生了什么。因此,在上面的情况下,如果我们要调用xargs
with -t
,我们会看到什么:
mv mbar bar mbaz baz
所以显然这是不正确的。发生的事情是,xargs
就像一条饥饿的鳄鱼,吃掉了通过管道喂给它的所有参数echo
。所以你需要一种方法来限制向 croc 释放参数。由于您是按行请求的,因此您需要的是-l
或-L
for 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
去掉回声,使功能真正发挥作用。