2

我的 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 变量,只要:

  • a) 不需要分叉来遍历变量的条目,并且
  • b) 人工解析和编辑所述变量的条目相当容易,并且
  • c) 它适用于 bash 3.2.x 以上版本。
4

3 回答 3

2

这将运行,sh所以我认为它会在bash 3.1. 它不喜欢regandvar参数替换 ( //,/) 所以我只是将它们更改为截断逗号。并将输入法更改为here-docvs 你的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
于 2012-04-16T14:44:39.980 回答
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
于 2012-04-16T13:56:11.957 回答
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 仅通过了一个参数,因此问题不是很清楚应该传递的参数是什么。如果是这样的话,那么这个问题就简单多了。

假设您正在使用带有数组的外壳,那么您绝对需要一个数组。不幸的是,Bash 缺少多维数组,而 bash <4.0 缺少关联数组,这基本上在间接和字符串中解析命令之间留下了选择——两者都很丑陋。就我个人而言,无论如何我都会尝试使用数组。

上述未记录的、不可移植的、不保证未来安全的 hack 在当前版本之前应该在 Bash 3 上“安全”并满足您的要求。bash 3 的限制非常痛苦,因为我们不能使用printf -v,并且没有分叉意味着没有命令替换,这意味着没有printf '%q'。基本上,heredoc 的每一行必须是通常是复合赋值的有效内容(正确引用和转义)。

http://mywiki.wooledge.org/BashFAQ/050

于 2012-04-16T19:21:20.537 回答