web-dev-qa-db-ja.com

awkを使用して行を配列に分割し、シェルの呼び出しでその配列の値を使用します

私はawkスクリプト内でbashを使用して、かなり一般的なタスクを実行しようとしています。適切に構造化されたファイル行を反復処理し、区切り文字で配列に分割します。ファイルのサンプルは次のとおりです。

Joe:Johnson:25
Sue:Miller:27

対話モードでこれを1行で行う方法の例は多数ありますが、bash自体のawkサブシェルの外でawkによって操作される配列を使用したいスクリプトで実行しています。

cat ${smryfile} | while read smryline; do

    echo ${smryline}

    #now i want to split the line into array 'linearray' in awk but have it usable when i get back to bash
    echo ${smryline} | awk '{split($0,$linearray,":")}'

    varX=$linearray[2]
    echo $varX
    #do something with $varX

done

エラーが発生します:

awk: syntax error at source line 1
 context is
     >>> {split($0,$linearray <<< ,":")}
awk: illegal statement at source line 1

私がやろうとしていること(スコープ外のawkで定義されている配列を使用)を実行することは可能ですか?

7
amphibient

私はあなたがawkなしであなたが望むことをすることができると思います:

cat "${smryfile}" | while IFS=: read first last varx
do
    echo "first='$first' last='$last' varx='$varx'"
    # do something
done

これにより、以下が生成されます。

first='Joe' last='Johnson' varx='25'
first='Sue' last='Miller' varx='27'

この方法は、ファイル内の名前にスペースが含まれている場合でも機能することに注意してください。

上記のcatを使用する必要がないことにも注意してください。

while IFS=: read first last varx
do
    echo "first='$first' last='$last' varx='$varx'"
    # do something
done <"${smryfile}"

上記のようにcatを削除することの副次的な利点は、ループで作成した変数がループの終了後も存続することです。

7
John1024

これはうまくいくはずです:

linearray=($(awk -F: '{$1=$1} 1' <<<"${smryline}"))
echo ${linearray[2]}
# output: 27

説明:awk -F::の入力を分割します。 awkはデフォルトで、変更された出力をスペースで区切るため、awkからの出力を使用してbash配列を直接作成できます。注変更された出力、つまり$1=$1へのno-op呼び出し。それ以外の場合、データは元の形式で出力されます。

しかし、例を挙げれば、awk -F:を使用して3番目の列を抽出し、出力をループしないでください。

awk -F: '{print $3}' "$smryfile" | while read varX; do
    echo $varX
done
6
grebneke

あなたがawkで解決策を求めたのは確かですが、sed解決策はもう少し明確だと思います。

str="Joe:Johnson:25"
array=($(echo "$str" | sed 's/:/ /g'))
for el in "${array[@]}"; do
    echo "el = $el"
done

これは与える:

el = Joe
el = Johnson
el = 25

この場合、コマンド展開を二重引用符で囲まないようにする必要があります。そのため、単一の文字列要素で終わることはありません。

もちろん、これはスペースを含む要素では機能しません。あなたが持っていた場合:

str="Joe:Johnson:25:Red Blue"

あなたは終わるだろう

el = Joe
el = Johnson
el = Red
el = Blue

ただし、evalを使用してもかまわない場合は、配列割り当ての前に引用符を挿入して機能させることができます。

eval "array=($(echo "\"$str\"" | sed 's/:/" "/g'))"

# Before the eval, it turns into:
eval "array=("Joe" "Johnson" "25" "Red Blue")"
0
krb686