如何使用自定义分隔符拆分一行并分配给 BASH 中的变量?
how to split one line with customized separator and assign to variables in BASH?
首先我使用 IFS 阅读,但后来我发现 -- IFS 只能支持单个字符作为分隔符,有时我需要一个字符串作为分隔符。
然后,我在想也许使用 awk 和 eval 可以做到。所以我试试--
eisen@PVGN34701109A:/tmp> cat file1
hah a#$hehe#$hoho
eisen@PVGN34701109A:/tmp> cat t2.sh
#!/bin/bash
eval $(awk -F'#\$' '{for (i=1;i<=NF;i++) print "VAR"i"='\''"$i"'\''"}' file1)
echo "VAR1= ${VAR1}"
echo "VAR2= ${VAR2}"
echo "VAR3= ${VAR3}"
eisen@PVGN34701109A:/tmp> ./t2.sh
awk: warning: escape sequence `$' treated as plain `$'
VAR1= hah a
VAR2= hehe
VAR3= hoho
起初,我觉得还好。但我立即发现了问题——在 file1 中,第一个值应该是“hah a”——里面有 3 个 space,但是在 awk 和 eval 之后——只剩下一个 space...
然后我分别用 awk 和 eval 进行了测试,我发现这是因为 eval 会“吃掉”一些 space--
eisen@PVGN34701109A:/tmp> eval "VAR1='hah a'";echo $VAR1
hah a
eisen@PVGN34701109A:/tmp> eval 'VAR1="hah a"';echo $VAR1
hah a
我自己找不到解决办法。请提供帮助,如果有任何其他更好的方法来拆分一行并分配给 BASH 中的变量,请分享您的想法。提前致谢。
我建议使用 shell 数组来存储单个字段值,并且 awk
略有不同:
IFS=$'' read -ra arr < <(awk -F'#\$' -v OFS='' '{=}1' file)
# check array content
declare -p arr
declare -a arr='([0]="hah a" [1]="hehe" [2]="hoho")'
我们使用控制字符 </code> 作为输出字段分隔符,并在 <code>IFS
中使用相同的字符来在 </code> 上创建 <code>read
拆分字段。
您也可以使用 sed
代替 awk
:
IFS=$'' read -ra arr < <(sed 's/#$/\x03/g' file)
在 BASH ver 4+
中使用 NUL 字节
readarray -d $'[=12=]' arr < <(
awk -F'#\$' -v OFS='[=12=]' '{ORS=OFS; =} 1' file)
#!/bin/bash
getVar(){
if [ "" -eq 0 ]; then
awk -F'#\$' '{for(i=1; i<=NF; i++) print $(i)}' file.txt;
else
awk -F'#\$' -v col="" '{printf $(col)}' file.txt;
fi
}
# assign variables
VAR1=$(getVar 1)
VAR2=$(getVar 2)
VAR3=$(getVar 3)
# using variables
echo "VAR1 ===${VAR1}==="
echo "VAR2 ===${VAR2}==="
echo "VAR3 ===${VAR3}==="
echo
# declare array
readarray -t my_array < <(getVar 0)
# dump
declare -p my_array|sed 's/declare -a //'
# using variables
echo "VAR1 ===${my_array[0]}==="
echo "VAR2 ===${my_array[1]}==="
echo "VAR3 ===${my_array[2]}==="
输出
VAR1 ===hah a===
VAR2 ===hehe===
VAR3 ===hoho===
my_array=([0]="hah a" [1]="hehe" [2]="hoho")
VAR1 ===hah a===
VAR2 ===hehe===
VAR3 ===hoho===
首先我使用 IFS 阅读,但后来我发现 -- IFS 只能支持单个字符作为分隔符,有时我需要一个字符串作为分隔符。 然后,我在想也许使用 awk 和 eval 可以做到。所以我试试--
eisen@PVGN34701109A:/tmp> cat file1
hah a#$hehe#$hoho
eisen@PVGN34701109A:/tmp> cat t2.sh
#!/bin/bash
eval $(awk -F'#\$' '{for (i=1;i<=NF;i++) print "VAR"i"='\''"$i"'\''"}' file1)
echo "VAR1= ${VAR1}"
echo "VAR2= ${VAR2}"
echo "VAR3= ${VAR3}"
eisen@PVGN34701109A:/tmp> ./t2.sh
awk: warning: escape sequence `$' treated as plain `$'
VAR1= hah a
VAR2= hehe
VAR3= hoho
起初,我觉得还好。但我立即发现了问题——在 file1 中,第一个值应该是“hah a”——里面有 3 个 space,但是在 awk 和 eval 之后——只剩下一个 space... 然后我分别用 awk 和 eval 进行了测试,我发现这是因为 eval 会“吃掉”一些 space--
eisen@PVGN34701109A:/tmp> eval "VAR1='hah a'";echo $VAR1
hah a
eisen@PVGN34701109A:/tmp> eval 'VAR1="hah a"';echo $VAR1
hah a
我自己找不到解决办法。请提供帮助,如果有任何其他更好的方法来拆分一行并分配给 BASH 中的变量,请分享您的想法。提前致谢。
我建议使用 shell 数组来存储单个字段值,并且 awk
略有不同:
IFS=$'' read -ra arr < <(awk -F'#\$' -v OFS='' '{=}1' file)
# check array content
declare -p arr
declare -a arr='([0]="hah a" [1]="hehe" [2]="hoho")'
我们使用控制字符 </code> 作为输出字段分隔符,并在 <code>IFS
中使用相同的字符来在 </code> 上创建 <code>read
拆分字段。
您也可以使用 sed
代替 awk
:
IFS=$'' read -ra arr < <(sed 's/#$/\x03/g' file)
在 BASH ver 4+
中使用 NUL 字节readarray -d $'[=12=]' arr < <(
awk -F'#\$' -v OFS='[=12=]' '{ORS=OFS; =} 1' file)
#!/bin/bash
getVar(){
if [ "" -eq 0 ]; then
awk -F'#\$' '{for(i=1; i<=NF; i++) print $(i)}' file.txt;
else
awk -F'#\$' -v col="" '{printf $(col)}' file.txt;
fi
}
# assign variables
VAR1=$(getVar 1)
VAR2=$(getVar 2)
VAR3=$(getVar 3)
# using variables
echo "VAR1 ===${VAR1}==="
echo "VAR2 ===${VAR2}==="
echo "VAR3 ===${VAR3}==="
echo
# declare array
readarray -t my_array < <(getVar 0)
# dump
declare -p my_array|sed 's/declare -a //'
# using variables
echo "VAR1 ===${my_array[0]}==="
echo "VAR2 ===${my_array[1]}==="
echo "VAR3 ===${my_array[2]}==="
输出
VAR1 ===hah a===
VAR2 ===hehe===
VAR3 ===hoho===
my_array=([0]="hah a" [1]="hehe" [2]="hoho")
VAR1 ===hah a===
VAR2 ===hehe===
VAR3 ===hoho===