将数组传递给Bash中的函数:语法错误,靠近意外令牌' ('

时间:2021-09-12 00:58:51

I am trying to pass a string array to a function in Bash which results in "syntax error near unexpected token `('"

我正在尝试将一个字符串数组传递给Bash中的一个函数,它会导致“接近意外令牌的语法错误”(')

 #!/usr/bin/env bash                                                                

 function __test() {                                                                
   my_command -c ("a" "b" "c" "d")                                                                                           
 } 

What am I doing wrong here ?

我在这里做错了什么?

2 个解决方案

#1


1  

It is a syntax violation, just do,

这是违反语法的,

function __test() {                                                                
   my_command -c "a" "b" "c" "d"                                                                                          
} 

to pass the four strings to my_command. The () is a syntax in bash for execution under a sub-shell which is probably not applicable here.

将四个字符串传递给my_command。()是bash中的一种语法,用于在子shell下执行,在这里可能不适用。

(or) using an array

(或)使用一个数组

function __test() { 
   local myArray=("a" "b" "c" "d" )                                                               
   my_command -c "${myArray[@]}"                                                                                         
} 

Your idea of using the array is right, but pass the array as a whole as ${myArray[@]} to the command.

您使用数组的想法是正确的,但是将数组作为一个整体作为${myArray[@]}传递给命令。

You asked for a getopts to handle this, and here is how you handle it. There are two ways to do this,

你要求一个getopts来处理这个问题,以下是你的处理方法。有两种方法,

To pass the arguments as a single quoted string "a b c d"

将参数作为单个引用的字符串“a b c d”传递

usage() { echo "Usage: $0 [-c args]" 1>&2; exit 1; }

[ $# -eq 0 ] && usage

while getopts ":c:" arg; do
  case $arg in
    c)
      IFS=' ' 
      argsC=($OPTARG)
      ;;

    *) 
      usage; exit 0
      ;;
  esac
done

printf "%s\n" "Number of arguments: ${#argsC[@]}"

and running now,

现在和运行,

./script.sh -c "a b c d"
Number of arguments: 4
a
b
c
d

and for sending as multiple strings, add the OPTARG value to the array, changing the getopts part alone,

对于以多个字符串的形式发送,将OPTARG值添加到数组中,只修改getopts部分,

while getopts ":c:" arg; do
  case $arg in
    c)
      argsC+=($OPTARG)
      ;;

    *) 
      usage; exit 0
      ;;
  esac
done

Now running the script,

现在运行脚本,

./script.sh -c "a" -c "b" -c "c" -c "d"
Number of arguments: 4
a
b
c
d
du

Use this [shell check] site for syntactically verifying your scripts.

使用这个[shell check]站点对脚本进行语法验证。

#2


2  

You cannot have Bash pass an array by reference, or have it copied as a single entity.

您不能让Bash通过引用传递数组,或者将其复制为单个实体。

There are two approaches to achieving the desired result.

有两种方法可以达到预期的结果。

The first one is copying the data

第一个是复制数据

 function __test()
 {
   declare -a array=("a" "b" "c" "d")
   my_command -c "${array[@]}"
 }

my_command()
{
  # Handle options
  [[ "$1" != -c ]] || shift
  # Get your data back in array form by collecting
  # positional parameters in an array
  declare -a array=("$@")
  # Display element at position 2
  echo "${array[2]}"
  # Display all elements
  echo "${array[@]}"
}

If mycommand is an external program in another language, then you would receive the data as positional parameters.

如果mycommand是另一种语言的外部程序,那么您将接收数据作为位置参数。

The second approach is indirection, and will only work if the data is used inside the same Bash script so that the variable can be access in the same scope.

第二种方法是间接的,并且只有当数据在同一个Bash脚本中使用时才能工作,这样变量才能在相同的范围中访问。

 function __test()
 {
   declare -a array=("a" "b" "c" "d")
   my_command -c array
 }

my_command()
{
  # Handle options
  [[ "$1" != -c ]] || shift
  varname="$1"
  # Access element at position 2
  x="$varname[2]"
  echo "${!x}"
  # Access all elements
  x="$varname[@]"
  echo "${!x}"
}

You need to make sure the variable name used does not contain any unwanted data, or else there could be risks or code injection, so unless the variable name is fully under the control of your program (no chance of user input being included in the variable name), you have to find a way to sanitize it.

您需要确保使用的变量名称不包含任何不必要的数据,否则可能会有风险或代码注入,所以除非变量名完全的控制下你的程序(没有用户输入的机会被包含在变量名),你必须找到一个方法来检查它。

Recent variables of bash have a -n option in variable declaration statements (such as local) which you may also want to take a look at, but I would think this is not deployed widely enough to be used except for known configurations.

bash的最近变量在变量声明语句(比如local)中有一个-n选项,您可能也想看看这个选项,但是我认为除了已知的配置外,这个选项的部署还不够广泛。

Please note that I would normally declare all variables local in functions unless I have a specific reason for not doing so, this has been omitted in the code above for clarity purposes.

请注意,我通常会在函数中声明所有变量,除非我有特定的理由不这样做,出于清晰的目的,在上面的代码中省略了这一点。

#1


1  

It is a syntax violation, just do,

这是违反语法的,

function __test() {                                                                
   my_command -c "a" "b" "c" "d"                                                                                          
} 

to pass the four strings to my_command. The () is a syntax in bash for execution under a sub-shell which is probably not applicable here.

将四个字符串传递给my_command。()是bash中的一种语法,用于在子shell下执行,在这里可能不适用。

(or) using an array

(或)使用一个数组

function __test() { 
   local myArray=("a" "b" "c" "d" )                                                               
   my_command -c "${myArray[@]}"                                                                                         
} 

Your idea of using the array is right, but pass the array as a whole as ${myArray[@]} to the command.

您使用数组的想法是正确的,但是将数组作为一个整体作为${myArray[@]}传递给命令。

You asked for a getopts to handle this, and here is how you handle it. There are two ways to do this,

你要求一个getopts来处理这个问题,以下是你的处理方法。有两种方法,

To pass the arguments as a single quoted string "a b c d"

将参数作为单个引用的字符串“a b c d”传递

usage() { echo "Usage: $0 [-c args]" 1>&2; exit 1; }

[ $# -eq 0 ] && usage

while getopts ":c:" arg; do
  case $arg in
    c)
      IFS=' ' 
      argsC=($OPTARG)
      ;;

    *) 
      usage; exit 0
      ;;
  esac
done

printf "%s\n" "Number of arguments: ${#argsC[@]}"

and running now,

现在和运行,

./script.sh -c "a b c d"
Number of arguments: 4
a
b
c
d

and for sending as multiple strings, add the OPTARG value to the array, changing the getopts part alone,

对于以多个字符串的形式发送,将OPTARG值添加到数组中,只修改getopts部分,

while getopts ":c:" arg; do
  case $arg in
    c)
      argsC+=($OPTARG)
      ;;

    *) 
      usage; exit 0
      ;;
  esac
done

Now running the script,

现在运行脚本,

./script.sh -c "a" -c "b" -c "c" -c "d"
Number of arguments: 4
a
b
c
d
du

Use this [shell check] site for syntactically verifying your scripts.

使用这个[shell check]站点对脚本进行语法验证。

#2


2  

You cannot have Bash pass an array by reference, or have it copied as a single entity.

您不能让Bash通过引用传递数组,或者将其复制为单个实体。

There are two approaches to achieving the desired result.

有两种方法可以达到预期的结果。

The first one is copying the data

第一个是复制数据

 function __test()
 {
   declare -a array=("a" "b" "c" "d")
   my_command -c "${array[@]}"
 }

my_command()
{
  # Handle options
  [[ "$1" != -c ]] || shift
  # Get your data back in array form by collecting
  # positional parameters in an array
  declare -a array=("$@")
  # Display element at position 2
  echo "${array[2]}"
  # Display all elements
  echo "${array[@]}"
}

If mycommand is an external program in another language, then you would receive the data as positional parameters.

如果mycommand是另一种语言的外部程序,那么您将接收数据作为位置参数。

The second approach is indirection, and will only work if the data is used inside the same Bash script so that the variable can be access in the same scope.

第二种方法是间接的,并且只有当数据在同一个Bash脚本中使用时才能工作,这样变量才能在相同的范围中访问。

 function __test()
 {
   declare -a array=("a" "b" "c" "d")
   my_command -c array
 }

my_command()
{
  # Handle options
  [[ "$1" != -c ]] || shift
  varname="$1"
  # Access element at position 2
  x="$varname[2]"
  echo "${!x}"
  # Access all elements
  x="$varname[@]"
  echo "${!x}"
}

You need to make sure the variable name used does not contain any unwanted data, or else there could be risks or code injection, so unless the variable name is fully under the control of your program (no chance of user input being included in the variable name), you have to find a way to sanitize it.

您需要确保使用的变量名称不包含任何不必要的数据,否则可能会有风险或代码注入,所以除非变量名完全的控制下你的程序(没有用户输入的机会被包含在变量名),你必须找到一个方法来检查它。

Recent variables of bash have a -n option in variable declaration statements (such as local) which you may also want to take a look at, but I would think this is not deployed widely enough to be used except for known configurations.

bash的最近变量在变量声明语句(比如local)中有一个-n选项,您可能也想看看这个选项,但是我认为除了已知的配置外,这个选项的部署还不够广泛。

Please note that I would normally declare all variables local in functions unless I have a specific reason for not doing so, this has been omitted in the code above for clarity purposes.

请注意,我通常会在函数中声明所有变量,除非我有特定的理由不这样做,出于清晰的目的,在上面的代码中省略了这一点。