[英]Bash Array expansion with entries containing whitespaces
将一个包含空格的数组传递给另一个 function 时遇到一个奇怪的问题。 当有问题的数组随后从目标 function 的上下文中扩展时,就会发生错误,似乎空格被错误地解释为分隔符,因此:
如何确保 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.
这是您当前正在执行的操作:
read -a
小心地将字符串拆分为正确的数组echo
连接所有带有空格的元素如果您只是跳过第 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.