如何使用逗号分隔列表作为下一个命令的参数


9

我有一个脚本s1,输出以','分隔的数字列表1,2,3,4。现在,我想将这些数字s2作为参数提供给脚本,以便s2将在每个数字上运行并在单独的行中输出其结果。例如,如果s2将数字乘以2,这就是我要查找的结果:

2
4
6
8

我现在正在做的是:

s1 | xargs -d "," | xargs -n1 s2

但是我觉得我这样做是愚蠢的!所以我的问题是:

正确的做法是什么?

我的解决方案的问题在于,它两次调用xargs并两次对输入进行迭代,这当然对我来说是不合理的。答案xargs -d "," -n1似乎不错,但我不确定是否只重复一次。如果是这样,请在您的回答中确认这一点,我会接受。顺便说一句,我宁愿不使用Perl,因为它仍在迭代两次,而且Perl在许多系统上可能不存在。


1
如果可行,为什么称其为愚蠢。如果执行时间很重要,那又是另一回事了
George Udosen

2
试试这个s1 | xargs -d "," -n1 s2
George Udosen

1
我怀疑其中一些问题误解了迭代的影响。遍历诸如关联数组之类的元素中的元素是不好的,这是因为遍历该数据结构的开销很大,但是“迭代”通常并不是固有的不好。具体地说,逐行读取STDIN中的数据并不是很大的性能问题。这里的性能问题更多是产生新流程和建立管道的成本。只要您不经常这样做(就像在循环中那样),担心xargs的性能可能就是过早优化的一个例子。
丹尼绍尔

Answers:


18

这同样应该起作用:

s1 | xargs -d "," -n1 s2

测试用例:

printf 1,2,3,4 | xargs -d ',' -n1 echo

结果:

1
2
3
4

如果s1输出该列表后跟换行符,则您希望将其删除,否则最后一次调用将使用4\n而不是4

s1 | tr -d '\n' | xargs -d , -n1 s2

6

如果s2可以接受多个参数,则可以执行以下操作:

(IFS=,; ./s2 $(./s1))

暂时将IFS覆盖为逗号,全部放在子外壳中,这样就可以s2看到s1逗号分隔的输出。子shell是更改IFS的快捷方式,而无需保存先前的值或将其重置。

该答案的先前版本不正确,可能是由于剩余的IFS设置破坏了结果。由于ilkkachu指出我的错误

要手动循环输出并将其单独提供给s2,此处演示了IFS的保存和重置:

oIFS="$IFS"
IFS=,
for output in $(./s1); do ./s2 "$output"; done
IFS="$oIFS"

或像以前一样在子Shell中运行IFS位:

(
IFS=,
for output in $(./s1); do ./s2 "$output"; done
)

1
您确定第一个吗?在我的系统上bash -c 'IFS=, printf "%s\n" $(echo 1,2,3)'打印1,2,3,即没有拆分。
ilkkachu

我会重新测试,但是我怀疑基于内置程序与外部程序的不同行为。
杰夫·谢勒

/usr/bin/printfand 相同/bin/echo
-ilkkachu

1
@ilkkachu您是正确的,(IFS=,; printf "%s\n" $(echo 1,2,3))另一方面,在这种情况下,应该在重新分配IFS之前进行单词拆分。
猫猫为莫妮卡(Monica)

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.