我的shell脚本似乎有点生疏。我的愿望是在bash中循环遍历arraylist配置变量,并使用在此循环内获得的必要参数调用函数,所有这些都没有分叉。
基本上,我创建了一个内部脚本人类可解析的逗号分隔配置变量,如下所示:
CONFIG="
0, 0x00, 'Reset the chip, enable PLL with P=4, R=1, J=9, D=6338' %
1, 0x01, 'Reset the chip, enable PLL with P=4, R=1, J=9, D=6338' %
51, 0x10, 'Reset the chip, enable PLL with P=4, R=1, J=9, D=6338' %
63, 0xd4, 'Power up and unmute DAC' %
64, 0x00, 'Power up and unmute DAC' %
"
我想像这样循环其参数:
while read reg val expl; do
printf "%s %s\n" "Calling i2c_write() with reg=${reg//,/}" \
"val=${val//,/} expl=$expl __EOL__";
# i2c_write() call
done <<< "${CONFIG//\%/$'\n'}"
目前的输出是:
Calling i2c_write() with reg= val= expl= __EOL__
Calling i2c_write() with reg=0 val=0x00 expl='Reset the chip, enable PLL with P=4, R=1, J=9, D=6338' __EOL__
Calling i2c_write() with reg= val= expl= __EOL__
Calling i2c_write() with reg=1 val=0x01 expl='Reset the chip, enable PLL with P=4, R=1, J=9, D=6338' __EOL__
Calling i2c_write() with reg= val= expl= __EOL__
Calling i2c_write() with reg=51 val=0x10 expl='Reset the chip, enable PLL with P=4, R=1, J=9, D=6338' __EOL__
Calling i2c_write() with reg= val= expl= __EOL__
Calling i2c_write() with reg=63 val=0xd4 expl='Power up and unmute DAC' __EOL__
Calling i2c_write() with reg= val= expl= __EOL__
Calling i2c_write() with reg=64 val=0x00 expl='Power up and unmute DAC' __EOL__
Calling i2c_write() with reg= val= expl= __EOL__
Calling i2c_write() with reg= val= expl= __EOL__
所需的输出是:
Calling i2c_write() with reg=0 val=0x00 expl='Reset the chip, enable PLL with P=4, R=1, J=9, D=6338' __EOL__
Calling i2c_write() with reg=1 val=0x01 expl='Reset the chip, enable PLL with P=4, R=1, J=9, D=6338' __EOL__
Calling i2c_write() with reg=51 val=0x10 expl='Reset the chip, enable PLL with P=4, R=1, J=9, D=6338' __EOL__
Calling i2c_write() with reg=63 val=0xd4 expl='Power up and unmute DAC' __EOL__
Calling i2c_write() with reg=64 val=0x00 expl='Power up and unmute DAC' __EOL__
我很高兴用更合适的结构替换CONFIG变量,只要:
答案 0 :(得分:2)
是否有必要保留这种错综复杂的CONFIG格式?
这应该有效:
#!/bin/bash
CONFIG="
0, 0x00, 'Reset the chip, enable PLL with P=4, R=1, J=9, D=6338'
1, 0x01, 'Reset the chip, enable PLL with P=4, R=1, J=9, D=6338'
51, 0x10, 'Reset the chip, enable PLL with P=4, R=1, J=9, D=6338'
63, 0xd4, 'Power up and unmute DAC'
64, 0x00, 'Power up and unmute DAC'
"
while IFS=,$'\n ' read -r reg val expl; do
[ -z "$reg" ] && continue
printf "%s %s\n" "Calling i2c_write() with reg=${reg}" \
"val=${val} expl=$expl __EOL__";
# i2c_write() call
done <<< "${CONFIG}"
我只是将%
替换为文字换行符,因为无论如何您之后都这样做了,并使,
也成为分隔符。我还进行了测试,跳过前导和尾随空行。
如果必须,您可以将%
保留为换行符,其余部分保持不变。
编辑:
如果您对保留令人费解的CONFIG格式更不满意,我可以提出以下备选方案吗?
#!/bin/bash
config+=(0 0x00 'Reset the chip, enable PLL with P=4, R=1, J=9, D=6338')
config+=(1 0x01 'Reset the chip, enable PLL with P=4, R=1, J=9, D=6338')
config+=(51 0x10 'Reset the chip, enable PLL with P=4, R=1, J=9, D=6338')
config+=(63 0xd4 'Power up and unmute DAC')
config+=(64 0x00 'Power up and unmute DAC')
for((i=0;i<${#config[@]};i+=3)) ; do
reg=${config[$i]}
val=${config[$i+1]}
expl="${config[$i+2]}"
printf "Calling i2c_write() with reg=%d val=%s expl='%s' __EOL__\n" \
$reg $val "$expl"
# i2c_write() call
done
这假设您总是有3个参数的集合,这看起来是正确的,并且避免了凌乱的解析逻辑。它应该稍微更高效。我还将printf
更改为更简单。
编辑2:
与Peter.O竞争,这是一个在sh
中运行的版本:
#!/bin/sh
CONFIG="
0, 0x00, 'Reset the chip, enable PLL with P=4, R=1, J=9, D=6338'
1, 0x01, 'Reset the chip, enable PLL with P=4, R=1, J=9, D=6338'
51, 0x10, 'Reset the chip, enable PLL with P=4, R=1, J=9, D=6338'
63, 0xd4, 'Power up and unmute DAC'
64, 0x00, 'Power up and unmute DAC'
"
echo "$CONFIG" | while IFS=' ', read -r reg val expl; do
[ -z "$reg" ] && continue
printf "Calling i2c_write() with reg=%d val=%s expl=%s __EOL__\n" \
$reg $val "$expl"
# i2c_write() call
done
答案 1 :(得分:2)
这将运行sh
所以我认为它将在bash 3.1
中运行。它不喜欢reg
和var
参数替换(//,/
)所以我只是将它们更改为截断逗号。并将输入法更改为here-doc
与here-string
我不确定为什么在每个输入行的末尾都有%
。只是在那里换一个换行符吗? (但是那里已经有了换行符,而%
替换只会添加空行)...
这是修改过的脚本
while read -r reg val expl; do
printf "%s %s %s\n" \
"Calling i2c_write() with reg=${reg%,}" \
"val=${val%,}" \
"expl=$expl __EOL__";
done <<EOF
0, 0x00, 'Reset the chip, enable PLL with P=4, R=1, J=9, D=6338'
1, 0x01, 'Reset the chip, enable PLL with P=4, R=1, J=9, D=6338'
51, 0x10, 'Reset the chip, enable PLL with P=4, R=1, J=9, D=6338'
63, 0xd4, 'Power up and unmute DAC'
64, 0x00, 'Power up and unmute DAC'
EOF
这是awk
版本(仅为了比较)。它读取相同的数据。
awk -vFS=\' '{split($1,f," ")
split(f[1]f[2],f,",")
print "Calling i2c_write() with" \
" reg=" f[1] \
" val=" f[2] \
" expl="FS $2 FS" __EOL__"
}' <<EOF
:: data ::
END
和sed
以获得良好的衡量标准......
sed -nr "s/^ +([0-9]+), +([0-9a-fx]+), +('.*')$/\
Calling i2c_write() with reg=\1 val=\2 expl=\3 __EOL__/p
" <<EOF
:: data ::
END
答案 2 :(得分:1)
main() {
local a n
while read -r a; do
local -a 'args=('"$a"')'
printf "%s reg=%s val=%s expl='%s' __EOL__\n" 'Calling i2c_write() with' "${args[@]}"
# i2c_write {reg,val,expl}"=${args[n++%3]}"
done <<"EOF"
0 0x00 'Reset the chip, enable PLL with P=4, R=1, J=9, D=6338'
1 0x01 'Reset the chip, enable PLL with P=4, R=1, J=9, D=6338'
51 0x10 'Reset the chip, enable PLL with P=4, R=1, J=9, D=6338'
63 0xd4 'Power up and unmute DAC'
64 0x00 'Power up and unmute DAC'
EOF
}
main
我假设你试图在这里存储3个字段的“结构”并将它们作为3个单独的参数传递。注释行是我期望你可能会调用命令的方式。问题不是很明确,因为你的printf只传递了一个,所以传递的参数应该是什么。如果是这种情况,那么这个问题就更简单了。
假设您正在使用带阵列的shell,您绝对需要一个数组。不幸的是,Bash缺少多维数组,并且bash&lt; 4.0缺少关联数组,这实际上是在间接和字符串中解析命令之间做出选择 - 这两者都是丑陋的。就个人而言,无论如何我都会尝试使用数组。
以上无证,不可移植,不保证未来安全的黑客应该在Bash 3上通过当前版本“安全”并满足您的要求。 bash 3限制非常痛苦,因为我们不能使用printf -v
,并且没有forks意味着没有命令替换,这意味着没有printf '%q'
。基本上,heredoc的每一行必须是通常为复合赋值的有效内容(正确引用和转义)。