Bash 使用从当前 shell 中的子 shell 返回的参数

Bash 使用从当前 shell 中的子 shell 返回的参数

抱歉,如果标题不好(这已经是我能想到的最好的标题了)。

无论如何,这是代码行:

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 的typesetorprintf %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 内置函数,因此在下面的示例中,我们不调用printfBash 内置函数,而是调用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

相关内容