bash:用包含空格和特殊字符的元素填充数组

bash:用包含空格和特殊字符的元素填充数组

我希望能够用任意字符串填充数组的元素,例如可能包含 \ 和空格的字符串。我写了这个:

#!/bin/bash
function populate_array () {
    if [ "$#" -gt 0 ] ; then
        # Enter array w/ elements as argument of executable 
        array=($@)
        n=$#
    else
        # Invoke executable with no arg,, enter array element later
        read -p "Enter array elements separated by spaces: " -a array  
        n=${#array[@]} 
    fi
    printf "%d array elements \n" "$n"
} 

populate_array "$@"

while (("$n" > 0))   # while [ "$n" -gt 0 ] ALSO WORKS
do
    printf "%s \n" "${array[$n-1]}"
    n=$n-1
done
exit 0

while 块仅用于检查数组元素。该函数非常简单,对于不包含space或 的参数来说,它可以很好地工作\。否则不行。

尝试向可执行文件输入以下参数:

#!> bash [scriptname] lkl1239 343.4l 3,344 (34) "lklk  lkl" lkaa\ lkc

我想看到 6 个论点:

lkl1239
343.4l 
3,344
(34)
lklk  lkl
lkaa lkc

相反,我被抛出:

  • 对于(=> bash:意外标记“34”附近有语法错误
  • 包含空格的字符串被解释为 x+1 字符串,其中 x 是字符串开头和结尾处不连续空格的数量。
  • Bash 会忽略第一次出现\

这是怎么做的?

答案1

你做的事情很棘手。正常的做法是避免这种情况,只将数组值作为参数传递。为了同时拥有这两个选项,你必须使用eval

#!/bin/bash
function populate_array () {
    if [ "$#" -gt 0 ] ; then
        # Enter array w/ elements as argument of executable 
        # Note the quotes, they are needed
        array=("$@");
        n=$#
    else
        # Invoke executable with no arg, enter array element later
        # Read a string instead of an array and use eval to make it
        # into an array. That way, you can use tricks like escaping
        # spaces. You also need the -r option to protect the backslashes
        # so that eval will see them. 
        read -r  -p "Enter array elements separated by spaces: " string
        eval array="( $(printf '%s\n' "$string") )"
        n=${#array[@]} 
    fi
    printf "%d array elements \n" "$n"
} 

populate_array "$@"

while (("$n" > 0))   # while [ "$n" -gt 0 ] ALSO WORKS
do
    printf "%s \n" "${array[$n-1]}"
    n=$n-1
done
exit 0

如果将数组值作为参数传递,则仍需要对括号进行转义,因为括号( )是 bash 的保留字符。注意这一点后,上述脚本应该可以按预期运行:

$ foo.sh lkl1239 343.4l 3,344 \(34\) "lklk  lkl" lkaa\ lkc
6 array elements 
lkaa lkc 
lklk  lkl 
(34) 
3,344 
343.4l 
lkl1239 

$ foo.sh
Enter array elements separated by spaces:  lkl1239 343.4l 3,344 \(34\) "lklk  lkl" lkaa\ lkc 
6 array elements 
lkaa lkc 
lklk  lkl 
(34) 
3,344 
343.4l 
lkl1239 

答案2

只需引用$@您在函数调用中正确执行的操作即可:

array=("$@")

正如man bash所说:

"$@"相当于"$1" "$2" ...

答案3

特殊字符通常必须用反斜杠进行转义,如下所示:

 $ array-script.sh   lkl1239 343.4l 3,344 \(34\) "lklk  lkl" lkaa\ lkc                                                                  
6 array elements 
lkaa lkc 
lklk  lkl 
(34) 
3,344 
343.4l 
lkl1239 

shell 将括号视为元字符,因此需要进行转义。lkaa\ lkc 中的反斜杠已经转义了 lkaa 和 lkc 之间的空格,因此这两个字符串被视为一个。与cd /home/user/bin/NAME\ WITH\ SPACE

来自man bash

   metacharacter
                  A character that, when unquoted, separates words.  One of the following:
                  |  & ; ( ) < > space tab

答案4

你可以尝试将下面的内容放在脚本顶部

SAVEIFS=$IFS
IFS=$(echo -en "\n\b")

IFS=$SAVEIFS 

在脚本的底部

相关内容