为什么将带引号的字符串传递给 Bash 函数并用作命令参数不能按预期工作?
Why does passing a quoted string to Bash function and using as command parameter doesn't work as expected?
我有这段代码调用 dialog
参数,应该创建一个只有一个条目的菜单:
!/bin/bash
menu() {
echo dialog --clear --stdout --title "Menu" --menu "menu" 0 0 0 # dialog --clear --stdout --title Menu --menu menu 0 0 0 1 "my menu item" 1
dialog --clear --stdout --title "Menu" --menu "menu" 0 0 0
}
echo $(menu "1 \"my menu item\"")
它确实创建了菜单,但它创建了 2 个菜单项而不是一个,并为菜单项添加了双引号。
如果我使用此代码,它会起作用:
!/bin/bash
echo dialog --clear --stdout --title "Menu" --menu "menu" 0 0 0 1 "my menu item" # dialog --clear --stdout --title Menu --menu menu 0 0 0 1 my menu item
dialog --clear --stdout --title "Menu" --menu "menu" 0 0 0 1 "my menu item"
可以看出,即使在第一种情况下菜单项参数用双引号括起来(见 echo),它也被解释为 3 个参数。
如何使第一个示例按预期工作?
试试这样的东西:
#!/usr/bin/env bash
menu() {
dialog \
--clear \
--stdout \
--title "Menu" \
--menu "menu" 0 0 0 \
"$@"
}
choice=$(
menu \
1 'my menu item' \
2 'my other menu item'
)
if [ -n "$choice" ]; then
printf 'Choice is %s\n.' "$choice"
else
echo 'Cancelled!'
fi
Why does passing a quoted string to Bash function and using as command parameter doesn't work as expected?
我不认为参数传递的工作方式与您预期的不同,而是 command-line 扩展,尤其是参数扩展。让我们举一个更说明性的例子:
analyze2() {
echo -n " $# words: "
for word; do
echo -n " $word"
done
echo
}
analyze() {
echo arg count: $#
for arg; do
echo $arg
analyze2 $arg
analyze2 "$arg"
done
}
现在称呼它:
$ analyze foo "bar baz" "\"African or European swallow?\""
arg count: 3
foo
1 words: foo
1 words: foo
bar baz
2 words: bar baz
1 words: bar baz
"African or European swallow?"
4 words: "African or European swallow?"
1 words: "African or European swallow?"
要记住的要点之一是,在命令中字面上出现的引号与参数扩展产生的引号之间存在差异。只有前者具有任何句法相关性,防止单词拆分和引号删除。参数扩展产生的报价只是数据。
How can I make the first example work as expected?
如果您希望 menu
函数将两个参数传递给 dialog
,则将两个参数传递给 it。在函数内部,您可以使用特殊参数 $*
和 $@
之一传递完整的参数列表。它们的不同之处在于在双引号内扩展它们的效果:"$*"
将所有参数扩展为一个 shell 单词,而 "$@"
将每个参数扩展为单独的 shell 单词.
!/bin/bash
menu() {
echo dialog --clear --stdout --title "Menu" --menu "menu" 0 0 0 "$@" # dialog --clear --stdout --title Menu --menu menu 0 0 0 1 "my menu item" 1
dialog --clear --stdout --title "Menu" --menu "menu" 0 0 0 "$@"
}
echo $(menu 1 "my menu item")
我有这段代码调用 dialog
参数,应该创建一个只有一个条目的菜单:
!/bin/bash
menu() {
echo dialog --clear --stdout --title "Menu" --menu "menu" 0 0 0 # dialog --clear --stdout --title Menu --menu menu 0 0 0 1 "my menu item" 1
dialog --clear --stdout --title "Menu" --menu "menu" 0 0 0
}
echo $(menu "1 \"my menu item\"")
它确实创建了菜单,但它创建了 2 个菜单项而不是一个,并为菜单项添加了双引号。
如果我使用此代码,它会起作用:
!/bin/bash
echo dialog --clear --stdout --title "Menu" --menu "menu" 0 0 0 1 "my menu item" # dialog --clear --stdout --title Menu --menu menu 0 0 0 1 my menu item
dialog --clear --stdout --title "Menu" --menu "menu" 0 0 0 1 "my menu item"
可以看出,即使在第一种情况下菜单项参数用双引号括起来(见 echo),它也被解释为 3 个参数。
如何使第一个示例按预期工作?
试试这样的东西:
#!/usr/bin/env bash
menu() {
dialog \
--clear \
--stdout \
--title "Menu" \
--menu "menu" 0 0 0 \
"$@"
}
choice=$(
menu \
1 'my menu item' \
2 'my other menu item'
)
if [ -n "$choice" ]; then
printf 'Choice is %s\n.' "$choice"
else
echo 'Cancelled!'
fi
Why does passing a quoted string to Bash function and using as command parameter doesn't work as expected?
我不认为参数传递的工作方式与您预期的不同,而是 command-line 扩展,尤其是参数扩展。让我们举一个更说明性的例子:
analyze2() {
echo -n " $# words: "
for word; do
echo -n " $word"
done
echo
}
analyze() {
echo arg count: $#
for arg; do
echo $arg
analyze2 $arg
analyze2 "$arg"
done
}
现在称呼它:
$ analyze foo "bar baz" "\"African or European swallow?\""
arg count: 3
foo
1 words: foo
1 words: foo
bar baz
2 words: bar baz
1 words: bar baz
"African or European swallow?"
4 words: "African or European swallow?"
1 words: "African or European swallow?"
要记住的要点之一是,在命令中字面上出现的引号与参数扩展产生的引号之间存在差异。只有前者具有任何句法相关性,防止单词拆分和引号删除。参数扩展产生的报价只是数据。
How can I make the first example work as expected?
如果您希望 menu
函数将两个参数传递给 dialog
,则将两个参数传递给 it。在函数内部,您可以使用特殊参数 $*
和 $@
之一传递完整的参数列表。它们的不同之处在于在双引号内扩展它们的效果:"$*"
将所有参数扩展为一个 shell 单词,而 "$@"
将每个参数扩展为单独的 shell 单词.
!/bin/bash
menu() {
echo dialog --clear --stdout --title "Menu" --menu "menu" 0 0 0 "$@" # dialog --clear --stdout --title Menu --menu menu 0 0 0 1 "my menu item" 1
dialog --clear --stdout --title "Menu" --menu "menu" 0 0 0 "$@"
}
echo $(menu 1 "my menu item")