web-dev-qa-db-ja.com

awkで区切り文字列を配列に分割する方法

パイプ記号|が含まれているときに文字列を分割する方法。それらを配列になるように分割したい。

私は試した

echo "12:23:11" | awk '{split($0,a,":"); print a[3] a[2] a[1]}'

これはうまくいきます。私の文字列が"12|23|11"のようなものであれば、どうやってそれらを配列に分割するのですか?

126
Mohamed Saligh

やってみました:

echo "12|23|11" | awk '{split($0,a,"|"); print a[3],a[2],a[1]}'
204

文字列をawkの配列に分割するには、関数 split() を使います。

 awk '{split($0, a, ":")}'
 #           ^^  ^  ^^^
 #            |  |   |
 #       string  |   delimiter
 #               |
 #               array to store the pieces

区切り文字が指定されていない場合は、デフォルトでスペースが使用されるFSが使用されます。

$ awk '{split($0, a); print a[2]}' <<< "a:b c:d e"
c:d

例えば:のようにセパレータをつけることができます。

$ awk '{split($0, a, ":"); print a[2]}' <<< "a:b c:d e"
b c

これはFSで設定するのと同じです。

$ awk -F: '{split($0, a); print a[1]}' <<< "a:b c:d e"
b c

Gawkでは、正規表現としてセパレータを指定することもできます。

$ awk '{split($0, a, ":*"); print a[2]}' <<< "a:::b c::d e" #note multiple :
b c

さらに、4番目のパラメータを使用して、区切り文字が各ステップで何をしているのかも確認できます。

$ awk '{split($0, a, ":*", sep); print a[2]; print sep[1]}' <<< "a:::b c::d e"
b c
:::

GNU awkのmanページ を引用しましょう。

split(string、array [、fieldsep [、seps]])

fieldsepで区切られたstringの部分に分割し、arrayの部分とseps配列の区切り文字列を格納します。最初の部分はarray[1]に、2番目の部分はarray[2]に格納されます。 3番目の引数の文字列値fieldsepは、分割する場所を記述する正規表現です[stringFSと同じように正規表現にすることができます)入力レコードを分割する場所)。 fieldsepを省略した場合は、FSの値が使用されます。 split()は作成された要素の数を返します。 sepsgawkの拡張子で、seps[i]array[i]array[i+1]の間の区切り文字列です。 fieldsepが単一スペースの場合、先頭の空白はseps[0]に、末尾の空白はseps[n]になります。ここで、nsplit()の戻り値です(つまり、配列の要素).

85
fedorqui

もっと具体的にしてください! 「うまくいかない」とはどういう意味ですか?正確な出力(またはエラーメッセージ)、あなたのOSとawkのバージョンを投稿してください:

% awk -F\| '{
  for (i = 0; ++i <= NF;)
    print i, $i
  }' <<<'12|23|11'
1 12
2 23
3 11

あるいは、splitを使って:

% awk '{
  n = split($0, t, "|")
  for (i = 0; ++i <= n;)
    print i, t[i]
  }' <<<'12|23|11'
1 12
2 23
3 11

編集:on Solaris処理するにはPOSIX awk(/ usr/xpg4/bin/awk)を使用する必要があります。正しく4000フィールド。

15
echo "12|23|11" | awk '{split($0,a,"|"); print a[3] a[2] a[1]}'
3
Schildmeijer

不要なforkおよびexecsystem呼び出しを呼び出すので、echo "..." | awk ...ソリューションは好きではありません。

私は少しひねりを加えたDimitreのソリューションを好む

awk -F\| '{print $3 $2 $1}' <<<'12|23|11'

または少し短いバージョン:

awk -F\| '$0=$3 $2 $1' <<<'12|23|11'

この場合、出力レコードはまとまっていますが、これは本当の条件なので、印刷されます。

この特定のケースでは、stdinのリダイレクトは awk 内部変数を設定することで回避できます。

awk -v T='12|23|11' 'BEGIN{split(T,a,"|");print a[3] a[2] a[1]}'

私は ksh をかなり長い間使っていましたが、 bash ではこれは内部の文字列操作で管理できました。前者の場合、元の文字列は内部ターミネータによって分割されます。後者の場合、文字列には常に1文字の区切り文字で区切られた数字のペアが含まれていると想定されます。

T='12|23|11';echo -n ${T##*|};T=${T%|*};echo ${T#*|}${T%|*}
T='12|23|11';echo ${T:6}${T:3:2}${T:0:2}

すべての場合の結果は

112312
2
TrueY

実際にはawkには 'Input Field Separator Variable'という機能があります link 。これが使い方です。実際には配列ではありませんが、内部の$変数を使用しています。単純な文字列を分割する場合は簡単です。

echo "12|23|11" | awk 'BEGIN {FS="|";} { print $1, $2, $3 }'
2
Sven
echo "12|23|11" | awk '{split($0,a,"|"); print a[3] a[2] a[1]}'

うまくいくはずです。

2
codaddict

冗談で? :)

echo "12|23|11" | awk '{split($0,a,"|"); print a[3] a[2] a[1]}'はどうですか

これは私の出力です:

p2> echo "12|23|11" | awk '{split($0,a,"|"); print a[3] a[2] a[1]}'
112312

それで結局それは働いていると思います。

1
duedl0r