使用换行符替换bash参数

时间:2012-04-16 12:32:04

标签: bash arraylist newline substitution

我的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向上。

3 个答案:

答案 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中运行。它不喜欢regvar参数替换(//,/)所以我只是将它们更改为截断逗号。并将输入法更改为here-dochere-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的每一行必须是通常为复合赋值的有效内容(正确引用和转义)。

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