假设我有一个列表/数组:
list=(a b c)
如何将每个元素回显到 xargs?就像是:
for v in list; do echo v; done; | xargs
有没有更简洁的方法?
答案1
printf '%s\n' "${list[@]}" | xargs
这将list
在其自己的行上打印 的每个元素,并且换行符分隔的列表将被传递到xargs
。
"${list[@]}"
将扩展到 的单独双引号元素list
。 printf
如果给出的参数多于格式化字符串中的占位符,将重用其格式化字符串。
然而,只有当元素不包含空格、单引号、双引号或反斜杠字符,不是空字符串(并且某些xargs
实现仅由文本组成并且不是_
并且相对较短)时,这才有效。
对于任意(不太长的 1)元素(不包含 NUL 字符,但当前版本的 bash 无论如何都无法在其变量中存储 NUL),您可以将列表作为大多数xargs
实现支持的 NUL 分隔记录传递-0
选项(将出现在 POSIX 标准的下一版本中):
{
[ "${#list[@]}" -eq 0 ] || printf '%s\0' "${list[@]}"
} | xargs
使用print0
辅助函数可能会有所帮助:
print0() {
[ "$#" -eq 0 ] || printf '%s\0' "$@"
}
print0 "${list[@]}" | xargs -0
请注意,对于空列表,除 NetBSD 外,该命令(echo
默认情况下)仍将在不带参数的情况下调用一次。可以使用该选项来避免这种-r
情况(也在 POSIX 标准的下一版本中)。
¹ 虽然xargs
旨在解决execve()
系统调用的限制,但它不会在中间删除单个参数,因此如果单个参数大于该限制,execve()
将无法执行该命令。 Linux 对单个参数的大小也有限制,这与大多数系统常见的所有参数和环境变量的累积大小的总体限制不同。
答案2
除非它是一个特别长的列表,否则您可以xargs
完全放弃
list=(a b c)
# With xargs
printf "%s\n" "${list[@]}" | xargs foo # Results in « foo a b c »
# Without xargs
foo "${list[@]}" # Also results in « foo a b c »
当然,这对您的情况的适用性取决于您想要传递给实际xargs
命令的附加标志(如果有)。
如果您想foo
对此进行测试,请运行此脚本并将上面的所有实例替换foo
为./foo
:
cat <<'EOF' > foo
#!/bin/bash
echo "Got $# arg(s): $*"
for ARG in "$@"; do echo "> $ARG <"; done
EOF
chmod a+x foo
另请注意,默认情况下(如此处所示),xargs
将其参数拆分为空格,因此:
list=('a b' c d) # Three arguments; the first contains a space
printf "%s\n" "${list[@]}" | xargs foo # Gives foo four arguments « a b c d »
foo "${list[@]}" # Gives foo three arguments, with the first containing a space, « 'a b' c d »