xargs |使用输入作为命令

xargs |使用输入作为命令

我本以为下面的例子工作得很好。

$ which -a python python3 pip | xargs -I {} {} --version
No '{}' such file or folder
$ which -a python python3 pip | xargs -I _ _ --version
No '_' such file or folder
$ which -a python python3 pip | xargs -I py py --version
No 'py' such file or folder

但当我以交互方式运行它时,它们根本不起作用,它甚至不替换字符串。我在手册页中没有看到有关第一个位置的特殊情况的注释。为什么这不起作用?

$ which -a python python3 pip | xargs -I py -p eval py --version
eval ~/.pyenv/shims/python --version?...y
xargs: eval: No such file or directory

这更令人惊讶,因为它确实替换正确。

我怎样才能首先使用这个论点?我不想使用,... -I py sh -c "py --version"因为这会创建一个新的子流程。我想知道如何在当前环境中评估命令。

答案1

xargs -I replstr utility argumentsPOSIX 要求只能replstr在 中被替换arguments,而不是utility。 GNUxargs在这方面是兼容的(busyboxxargs不是)。

要解决这个问题,您可以使用env以下实用程序:

which -a ... | xargs -I cmd xargs env cmd --version

(由于xargs解释其输入的方式,导致前导空格、反斜杠、单引号、双引号、换行符、可能的字节序列或形成有效字符的阻塞)。

或更好:

for cmd in (which -a ...)
  $cmd --version
end

这会将文件名中的有问题的字符限制为仅换行符。

无论如何,你不能也不想eval在这里使用。eval是 shell 内置命令(POSIX shell 中的特殊内置命令),用于解释 shell 代码,而不是运行命令。xargs是 shell 的外部命令,因此如果不启动该 shell 的解释器,它就无法运行 shell 或任何 shell 的内置命令,如下所示:

which -a ... |
  xargs -rd '\n' sh -c 'for cmd do "$cmd" --version; done' sh

使用sh而不是fish此处,因为据我所知fish内联脚本不能接受参数。但仍然不是在这里使用eval这是没有意义的,因为我们不希望这些文件名被解释为 shell 代码。

还使用-rd '\n'GNU 特定的但不存在 的所有问题-I,将所有行的完整内容作为单独的参数传递给实用程序(此处sh)。

相关内容