问题描述
我有这段代码,它使用参数调用dialog
并应创建一个具有单个条目的菜单:
!/bin/bash
menu() {
echo dialog --clear --stdout --title "Menu" --menu "menu" 0 0 0 $1 # 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 $1
}
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
,
为什么将带引号的字符串传递给Bash函数并用作命令参数不能按预期工作?
我认为不是参数传递的工作原理与您期望的不同,而是命令行扩展,尤其是参数扩展。让我们举一个更具说明性的示例:
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?"
要带走的关键点是,实际在命令中出现的引号与由参数扩展引起的引号之间存在差异。只有前者具有任何语法相关性,可防止单词拆分和引号删除。参数扩展产生的引号只是数据。
如何使第一个示例按预期工作?
如果您希望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")