繁体   English   中英

Bash 数组扩展,条目包含空格

[英]Bash Array expansion with entries containing whitespaces

将一个包含空格的数组传递给另一个 function 时遇到一个奇怪的问题。 当有问题的数组随后从目标 function 的上下文中扩展时,就会发生错误,似乎空格被错误地解释为分隔符,因此:

  1. 不保留每个数组条目中每个单词之间的空格。
  2. 每个直接以空格开头的单词在结果数组中占据一个单独的索引。

如何确保 arrays 传递给 function 在后续扩展后保留其条目中的任何空格?

以下代码可用于重现错误:

function caller(){

  #string to convert to array.
  str="var1=val1,var2=val2,var3=value\ with\ a\ space"

  #convert argument string to full name value pairs array
  fullNameValPairsArr=($(toNameValuePairsArray "$str"))

  callee fullNameValPairsArr    
}


#called by the top-level "caller" function and passed the array as an argument
function callee(){

  passedArray=$1[@]

  expandedPassedArray=("${!passedArray}")

  for curEntry in "${expandedPassedArray[@]}"
  do
    
       echo $curEntry
  
  done    

 }



#helper function converts arg string to name value pairs array.
function toNameValuePairsArray(){

  #store args string to local
  fullNameValPairsString="$1"

  #first split the full name-value pair parameters(via comma delimiter).
  IFS=','

  #Read the split words into an array based on space delimiter
  read -a nameValPairsArr <<< "$fullNameValPairsString"

 
  echo "${nameValPairsArr[@]}"      

}

caller

从调用到顶级“调用者”function 的 output 是:

var1=val1                                                                                                                                                    
var2=val2                                                                                                                                                    
var3=value                                                                                                                                                   
with                                                                                                                                                         
a                                                                                                                                                            
space 

如您所见,最后一个包含空格的参数(即带有空格的值)被拆分为数组中的几个单独的条目; 不保留字符串中的空格。

这是您的主要错误:

  fullNameValPairsArr=($(toNameValuePairsArray "$str"))

由于命令替换未加引号,shell 将对 output 执行分词,将带空格的参数分成单独的词。


我会使用“namerefs”,它允许您将变量名称传递给函数。
需要 bash 版本 4.3+。
参见手册中的Shell参数

if declare -n a=b 2>/dev/null; then
    unset a
else
    echo "This bash version ($BASH_VERSION) does not implement namerefs." >&2
    exit 1
fi

caller() {
    local str="var1=val1,var2=val2,var3=value\ with\ a\ space"
    local -a fullNameValPairsArr    

    toNameValuePairsArray "$str" fullNameValPairsArr    

    callee fullNameValPairsArr    
}


callee() {
    local -n passedArray=$1
    for curEntry in "${passedArray[@]}"; do
        echo "$curEntry"
    done    
}


toNameValuePairsArray() {
    local fullNameValPairsString="$1"
    local -n _ary=$2      # cannot use same varname as caller

    # don't set *global* IFS
    IFS=',' read -a _ary <<< "$fullNameValPairsString"
}

caller

输出

var1=val1
var2=val2
var3=value with a space

我会 go 更进一步,并将输入解析为关联数组:

# check bash version...

caller() {
    local str="var1=val1,var2=val2,var3=value\ with\ a\ space"
    #local -a fullNameValPairsArr    
    local -A fullNameValPairsArr    

    toNameValuePairsArray "$str" fullNameValPairsArr    

    callee fullNameValPairsArr    
}


callee() {
    local -n passedArray=$1
    for idx in "${!passedArray[@]}"; do
        echo "$idx => ${passedArray[$idx]}"
    done    
}


toNameValuePairsArray() {
    local fullNameValPairsString="$1"
    local -n _ary=$2      # cannot use same varname as caller

    # don't set *global* IFS
    IFS=',' read -a pairs <<< "$fullNameValPairsString"
    for pair in "${pairs[@]}"; do
        IFS="=" read var value <<<"$pair"
        _ary[$var]=$value
    done
}

caller

输出

var1 => val1
var2 => val2
var3 => value with a space

最后一点,bash 5.1 提供了一个新的可加载csv命令

BASH_LOADABLES_PATH="${BASH%/bin/bash}/lib/bash"
enable -f csv csv

str="var1=val1,var2=val2,var3=value\ with\ a\ space"
csv -a pairs "$str"

declare -p pairs

结果

declare -a pairs=([0]="var1=val1" [1]="var2=val2" [2]="var3=value\\ with\\ a\\ space")

文档:

$ help csv
csv: csv [-a ARRAY] string
    Read comma-separated fields from a string.

    Parse STRING, a line of comma-separated values, into individual fields,
    and store them into the indexed array ARRAYNAME starting at index 0.
    If ARRAYNAME is not supplied, "CSV" is the default array name.

这是您当前正在执行的操作:

  1. 使用read -a小心地将字符串拆分为正确的数组
  2. 立即用echo连接所有带有空格的元素
  3. 用分词分割空格上的所有元素

如果您只是跳过第 2 步和第 3 步,您将不会遇到此问题。

没有从 bash 函数返回值的好方法,但您可以使用全局变量:

function caller(){
  #string to convert to array.
  str="var1=val1,var2=val2,var3=value\ with\ a\ space"

  #convert argument string to full name value pairs array
  toNameValuePairsArray "$str"

# Copy from the global variable to an array of our choice
  fullNameValPairsArr=( "${toNameValuePairsArray_result[@]}" )
  callee fullNameValPairsArr
}

#called by the top-level "caller" function and passed the array as an argument
function callee(){
  passedArray=$1[@]
  expandedPassedArray=("${!passedArray}")
  for curEntry in "${expandedPassedArray[@]}"
  do
       echo $curEntry
  done
 }

#helper function converts arg string to name value pairs array.
function toNameValuePairsArray(){
  #store args string to local
  fullNameValPairsString="$1"
  #first split the full name-value pair parameters(via comma delimiter).
  IFS=','
  # "return" by assigning to a global variable
  read -a toNameValuePairsArray_result <<< "$fullNameValPairsString"
}

caller

这导致:

var1=val1
var2=val2
var3=value with a space

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM