![Bash 使用从当前 shell 中的子 shell 返回的参数](https://linux22.com/image/209934/Bash%20%E4%BD%BF%E7%94%A8%E4%BB%8E%E5%BD%93%E5%89%8D%20shell%20%E4%B8%AD%E7%9A%84%E5%AD%90%20shell%20%E8%BF%94%E5%9B%9E%E7%9A%84%E5%8F%82%E6%95%B0.png)
抱歉,如果标题不好(这已经是我能想到的最好的标题了)。
无论如何,这是代码行:
printf "%s\n" "$(echo a b "c d")
简单的代码。当然,稍后我会用我自己的代码替换它。这个例子已经足够解释了。
上面的代码输出:
a b c d
当我希望的输出是:
a
b
c d
通过使用子shell。
总而言之,答案中代码的“结构”应该与问题中的第一个代码片段大致相似。
这可能吗?任何帮助都会很棒。
PS 如果评论提出要求,我将编辑我的问题以改进问题。
答案1
对于打印任意字符串列表,然后可以在 bash 中作为数组导入的内容,您可以使用 NUL 分隔列表(因为 bash 变量无论如何都不能包含 NUL 字符),您可以使用该列表导入readarray -td ''
(假设 bash-4.4 +):
print0() { [ "$#" -eq 0 ] || printf '%s\0' "$@"; }
readarray -td '' list <(print0 a b "c d" $'e\nf')
或者让它打印数组定义typeset -p
并使用 导入eval
,这也将允许传递稀疏数组或多个数组:
eval "$( list=(a b "c d" $'e\nf'); typeset -p list)"
您可以为其定义一个助手:
print_array() {
eval "local $1"='( "${@:2}" )'
typeset -p "$1"
}
bash-5.0$ eval "$(print_array list a b 'b c' $'e\nf')"
bash-5.0$ printf ' - <%s>\n' "${list[@]}"
- <a>
- <b>
- <b c>
- <e
f>
请注意,如果从函数内调用,则数组最终将位于函数的本地,因为typeset
它前置于declare -a
数组定义。
您还可以将其打印set -- a b 'c d'...
以导入到位置参数中:
set_argv() { printf 'set --'; [ "$#" -eq 0 ] || printf ' %q' "$@"; }
bash-5.0$ eval "$(set_argv a b 'b c' $'e\nf')"
bash-5.0$ printf ' - <%s>\n' "$@"
- <a>
- <b>
- <b c>
- <e
f>
请注意,bash 的typeset
orprintf %q
并不总是使用最安全的引用方法,因此要小心与评估该输出相关的潜在风险。
答案2
对于给定的示例,您应该使用数组。看数组和参数扩展来自Bash 手册页有关数组的更多信息。
args=(a b "c d")
printf '%s\n' "${args[@]}"
如果您需要使用命令的输出作为参数,您可以使用IFS
参数作为参数分隔符和命令替换。由于通配符是在分词后执行的,因此您可能需要暂时禁用通配符,而且重要的是要注意在分词期间空项目将被丢弃(感谢斯蒂芬·查泽拉斯用于提醒)。
# save previous IFS value and change it to line feed
OLDIFS=$IFS IFS=$'\n'
# temporarily disable globbing if needed
#set -o noglob
# save command output to array, words are separated by IFS
args=($(printf 'arg 1\narg 2\narg 3\n'))
# reenable globbing if needed
#set +o noglob
# restore IFS
IFS=$OLDIFS
# expand array as command arguments
printf '%s\n' "${args[@]}"
使用xargs
可能是一个更简单的选择,但不要忘记它不是 shell 内置函数,不能直接调用 shell 内置函数,因此在下面的示例中,我们不调用printf
Bash 内置函数,而是调用printf
二进制文件(通常位于/bin/printf
或/usr/bin/printf
)。
# POSIX xargs requires quoting
printf '"arg 1" "arg 2" "arg 3"' | xargs printf '<arg>%s</arg>\n'
# other xargs (like GNU) versions have a `-d` delimiter option
printf 'arg 1\narg 2\narg 3' | xargs -d'\n' printf '<arg>%s</arg>\n'
GNU 和其他语言xargs
也有一个(非标准)-0
选项,允许用空字符(通常表示为'\0'
)分隔参数,这非常方便,因为参数不能包含空字节。其他命令考虑到这一点,允许使用空字节分隔项目,就像许多find
版本一样,其中包括-print0
使用 分隔找到的文件的选项'\0'
,尽管这不是标准选项。
# find files under /bin and calculate their sha256 digests
find /bin/ -type f -print0 | xargs -0 sha256sum