我本以为下面的例子工作得很好。
$ 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 arguments
,POSIX 要求只能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
)。