为什么将带引号的字符串传递给Bash函数并用作命令参数不能按预期工作?

问题描述

我有这段代码,它使用参数调用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个菜单项而不是一个,并在菜单项中添加了双引号。

enter image description here


如果我使用此代码,它将起作用:

!/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"

enter image description here

可以看出,即使在第一种情况下,菜单项参数用双引号引起(请参见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")

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...