BASH shell 用变量中的空格扩展参数
BASH shell expand arguments with spaces from variable
假设我有一个变量 $ARGS
,其中包含以下内容:
file1.txt "second file.txt" file3.txt
如何将 $ARGS
的内容作为参数传递给命令(例如 cat $ARGS
),将 "second file.txt"
视为一个参数而不将其拆分为 "second
和 file.txt"
?
理想情况下,我希望能够将参数完全按照存储在变量中的方式传递给任何命令(从文本文件读取,但我认为这不相关)。
谢谢!
正如 Jonathan Leffler 所提到的,您可以使用数组来做到这一点。
my_array=( "file1.txt" "second file.txt" "file3.txt" )
cat "${my_array[1]}"
数组的索引从 0 开始。因此,如果您想 cat
数组中的第一个文件,您可以使用索引号 0。"${my_array[0]}"
。如果您想对所有元素执行 运行 命令,请将索引号替换为 @
或 *
。例如,您可以使用 "${my_array[@]}"
而不是 "${my_arryay[0]}"
确保引用数组,否则它会将任何带有空格的文件名视为单独的文件。
或者,如果由于某种原因引用数组有问题,您可以将 IFS(代表内部字段分隔符)设置为等于换行符。如果这样做,最好在更改默认 IFS 之前将其保存到变量,这样您就可以将其设置回脚本完成后的状态。例如:
# save IFS to a variable
old_IFS=${IFS-$' \t\n'}
#set IFS to a newline
IFS='$\n'
# run your script
my_array=( "file1.txt" "second file.txt" "file3.txt" )
cat ${my_array[1]}
# restore IFS to its default state
IFS=$old_IFS
除非万不得已,否则最好不要乱用 IFS。如果您可以引用数组以使您的脚本工作,那么您应该这样做。
要更深入地了解如何使用数组,请参阅:
如果没有 bash
isms,普通 shell 代码可能需要一个 eval
:
# make three temp files and list them.
cd /tmp ; echo ho > ho ; echo ho ho > "ho ho" ; echo ha > ha ;
A='ho "ho ho" ha' ; eval grep -n '.' $A
输出:
ho:1:ho
ho ho:1:ho ho
ha:1:ha
注意eval
强大,if not used responsibly can lead to mischief...
可以在没有 bash 数组或 eval
的情况下执行此操作:这是 xargs
没有 -0
或 -d
扩展(一种主要产生错误的行为)实际上很有用。
# this will print each argument on a different line
# ...note that it breaks with arguments containing literal newlines!
xargs printf '%s\n' <<<"$ARGS"
...或...
# this will emit arguments in a NUL-delimited stream
xargs printf '%s[=11=]' <<<"$ARGS"
# in bash 4.4, you can read this into an array like so:
readarray -t -d '' args < <(xargs printf '%s[=11=]' <<<"$ARGS")
yourprog "${args[@]}" # actually run your programs
# in bash 3.x or newer, it's just a bit longer:
args=( );
while IFS= read -r -d '' arg; do
args+=( "$arg" )
done < <(xargs printf '%s[=11=]' <<<"$ARGS")
yourprog "${args[@]}" # actually run your program
# in POSIX sh, you can't safely handle arguments with literal newlines
# ...but, barring that, can do it like this:
set --
while IFS= read -r arg; do
set -- "$@" "$arg"
done < <(printf '%s\n' "$ARGS" | xargs printf '%s\n')
yourprog "$@" # actually run your program
...或者,让 xargs
自己执行调用:
# this will call yourprog with ARGS given
# ...but -- beware! -- will cause bugs if there are more arguments than will fit on one
# ...command line invocation.
printf '%s\n' "$ARGS" | xargs yourprog
假设我有一个变量 $ARGS
,其中包含以下内容:
file1.txt "second file.txt" file3.txt
如何将 $ARGS
的内容作为参数传递给命令(例如 cat $ARGS
),将 "second file.txt"
视为一个参数而不将其拆分为 "second
和 file.txt"
?
理想情况下,我希望能够将参数完全按照存储在变量中的方式传递给任何命令(从文本文件读取,但我认为这不相关)。
谢谢!
正如 Jonathan Leffler 所提到的,您可以使用数组来做到这一点。
my_array=( "file1.txt" "second file.txt" "file3.txt" )
cat "${my_array[1]}"
数组的索引从 0 开始。因此,如果您想 cat
数组中的第一个文件,您可以使用索引号 0。"${my_array[0]}"
。如果您想对所有元素执行 运行 命令,请将索引号替换为 @
或 *
。例如,您可以使用 "${my_array[@]}"
而不是 "${my_arryay[0]}"
确保引用数组,否则它会将任何带有空格的文件名视为单独的文件。
或者,如果由于某种原因引用数组有问题,您可以将 IFS(代表内部字段分隔符)设置为等于换行符。如果这样做,最好在更改默认 IFS 之前将其保存到变量,这样您就可以将其设置回脚本完成后的状态。例如:
# save IFS to a variable
old_IFS=${IFS-$' \t\n'}
#set IFS to a newline
IFS='$\n'
# run your script
my_array=( "file1.txt" "second file.txt" "file3.txt" )
cat ${my_array[1]}
# restore IFS to its default state
IFS=$old_IFS
除非万不得已,否则最好不要乱用 IFS。如果您可以引用数组以使您的脚本工作,那么您应该这样做。
要更深入地了解如何使用数组,请参阅:
如果没有 bash
isms,普通 shell 代码可能需要一个 eval
:
# make three temp files and list them.
cd /tmp ; echo ho > ho ; echo ho ho > "ho ho" ; echo ha > ha ;
A='ho "ho ho" ha' ; eval grep -n '.' $A
输出:
ho:1:ho
ho ho:1:ho ho
ha:1:ha
注意eval
强大,if not used responsibly can lead to mischief...
可以在没有 bash 数组或 eval
的情况下执行此操作:这是 xargs
没有 -0
或 -d
扩展(一种主要产生错误的行为)实际上很有用。
# this will print each argument on a different line
# ...note that it breaks with arguments containing literal newlines!
xargs printf '%s\n' <<<"$ARGS"
...或...
# this will emit arguments in a NUL-delimited stream
xargs printf '%s[=11=]' <<<"$ARGS"
# in bash 4.4, you can read this into an array like so:
readarray -t -d '' args < <(xargs printf '%s[=11=]' <<<"$ARGS")
yourprog "${args[@]}" # actually run your programs
# in bash 3.x or newer, it's just a bit longer:
args=( );
while IFS= read -r -d '' arg; do
args+=( "$arg" )
done < <(xargs printf '%s[=11=]' <<<"$ARGS")
yourprog "${args[@]}" # actually run your program
# in POSIX sh, you can't safely handle arguments with literal newlines
# ...but, barring that, can do it like this:
set --
while IFS= read -r arg; do
set -- "$@" "$arg"
done < <(printf '%s\n' "$ARGS" | xargs printf '%s\n')
yourprog "$@" # actually run your program
...或者,让 xargs
自己执行调用:
# this will call yourprog with ARGS given
# ...but -- beware! -- will cause bugs if there are more arguments than will fit on one
# ...command line invocation.
printf '%s\n' "$ARGS" | xargs yourprog