2

私のシェルスクリプトは少し錆びているようです。私の望みは、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

この複雑な 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 つのパラメーターのセットがあることを前提としています。これは true に見え、面倒な解析ロジックを回避します。少し効率が上がるはずです。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 に答える
2

これは実行されるshので、で実行されると思いますbash 3.1regvarパラメータの置換 ( ) が気に入らなかった//,/ので、コンマを切り捨てるように変更しました。入力方法を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 に答える
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 が1つだけ渡されるため、渡される引数がどうあるべきかについての質問はあまり明確ではありません。もしそうなら、この問題ははるかに簡単です。

配列を持つシェルを使用していると仮定すると、絶対に配列が必要になります。残念ながら、Bash には多次元配列がなく、bash <4.0 には連想配列がありません。これにより、実質的に間接化と文字列内のコマンドの解析のどちらかを選択できます。どちらも醜いものです。個人的には、とにかく配列を使用してみます。

上記の文書化されておらず、移植性がなく、将来的に安全であることが保証されていないハックは、現在のバージョンまで Bash 3 で「安全」であり、要件を満たしている必要があります。を使用できないためprintf -v、bash 3 の制限は非常に苦痛であり、フォークがないということは、コマンド置換がないことを意味し、つまり、がないことを意味しprintf '%q'ます。基本的に、ヒアドキュメントの各行は、通常は複合代入の有効な内容でなければなりません (適切に引用され、エスケープされます)。

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

于 2012-04-16T19:21:20.537 に答える