在为字符串替换编写 Bash 函数时,我在使用 xargs 时遇到了一个奇怪的行为。这实际上让我发疯,因为我无法让它工作。 幸运的是,我已经能够将其归结为以下简单示例:
定义一个简单的函数,将给定参数的每个字符加倍:
function subs { echo $1 | sed -E "s/(.)/\1\1/g"; }
调用函数:
echo $(subs "ABC")
正如预期的那样,输出是:
AABBCC
现在使用 xargs 调用函数:
echo "ABC" | xargs -I % echo $(subs "%")
令人惊讶的是现在的结果是:
ABCABC
似乎函数内的 sed 命令现在将整个字符串视为单个字符。 为什么会发生这种情况,如何预防?
您可能会问,我为什么要使用 xargs。当然,这是一个简化的示例,实际用例要复杂得多。
在最初的用例中,我有一个产生大量输出的程序。我通过几个 greps 管道输出以获得感兴趣的行。之后,我将这些行通过管道传输到 sed 以从这些行中提取我需要的数据。因为我需要对数据进行的一些转换太复杂而无法单独使用正则表达式,所以我想为这些使用一个函数。所以,我最初的想法是简单地通过管道输入函数,但我无法让它工作并最终得到 xargs 解决方案。我最初的想法是这样的:
command | grep ... | grep ... | grep ... | sed ... | subs
顺便说一句:我不是从命令行而是从脚本中执行此操作。该函数在使用它的同一个脚本中定义。
我正在使用 Bash 3.2(Mac OS X 默认),所以花哨的 Bash 4.x 东西对我没有帮助,抱歉。
我会很高兴所有可能对这个主题有所启发的事情。
最好的问候
弗兰克
最佳答案
如果您真的需要这样做(您可能不需要,但如果没有更具代表性的样本我们无能为力),更好的实践方法可能如下所示:
subs() { sed -E "s/(.)/\1\1/g" <<<"$1"; }
export -f subs
echo "ABC" | xargs bash -c 'for arg; do subs "$arg"; done' _
- 使用
echo "$(subs "$arg")"
而不是仅仅subs "$arg"
只会增加错误(考虑如果其中之一会发生什么你的论点是-n
——这是假设一个相对温和的echo
;即使没有-e
论点,它们也可以使用反斜杠,并且做各种其他令人惊讶的事情)。您可以在上面这样做,但它会减慢您的程序速度并使其更容易出现令人惊讶的行为;没有意义。 - 运行
export -f subs
将您的函数导出到环境中,因此它可以由作为子进程调用的其他 bash 实例运行(所有由xargs
调用的程序都是在你的 shell 之外,所以他们看不到 shell 局部变量或函数)。 没有
-I
——也就是说,在它的默认操作模式下——xargs
将参数附加到它给出的命令的末尾。这允许一种更有效的使用模式,而不是每行输入调用一个命令,而是将尽可能多的参数传递给尽可能少的子进程。这也避免了将
xargs -I
与bash -c '...'
或sh -c ' 结合使用时可能发生的重大安全漏洞...'
。 (如果你曾经使用过-I% sh -c '...%...'
,那么你的文件名就会成为你代码的一部分,并且能够用于对你的系统进行注入(inject)攻击) .
关于linux - 如何使用 xargs 在每个匹配项的命令替换中运行一个函数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54768307/