2

$fileは、59列と64行のcsv(タブ区切り)です。列1は常に文字列であり、列2+は常に整数です(値がの場合は1回を除くNULL)。

cat ${file} | while read line 
    do awk -F'\t' '{ for (i=2; i<=NF; i++) print $1 "\t" $i "." }';
    done;

出力:

Excellent   .
Good    .
…

それでも作品$iに切り替える$2

Excellent   29.
Good    7.
…

なぜ??

編集

#lines 1 & 2 from data.csv (columns truncated for brevity):
Excellent   29  54  47  46  38  22  50
Good    7   14  27  24  26  36  20

#reform.sh
file=$1;
awk -F'\t' '{ for (i=2; i<=NF; i++) print $1 "\t" $i; }' ${file};

それでも前と同じように動作/戻ります。

解決策

承認された回答は、AWKからの適切な出力を提供します。ターミナルアプリケーションを再起動した後、スクリプトは説明どおりに実行されました。ターミナルアプリの問題の原因を特定できませんでした。

4

2 に答える 2

7

私はあなたが間違っていると思います。あなたが持っているスクリプトは、インテリジェントなものを何も出力しません(a)。なぜなら、各行をに読み込もうとしている間$line、実際にはそれらをに与えていないからawkです。

次のような方法で、余分な(そして正しくない)ループを取り除くことができます。

awk -F'\t' '{ for (i=2; i<=NF; i++) print $1 "\t" $i "." }' ${file}

次のトランスクリプトに示されているように:

pax> echo 'A 1 2
...> B 3 4
...> C 5 6' >qq.in

pax> cat qq.in
A 1 2
B 3 4
C 5 6

pax> awk -F' ' '{ for (i=2; i<=NF; i++) print $1 " " $i "." }' qq.in
A 1.
A 2.
B 3.
B 4.
C 5.
C 6.

ご覧のとおり(タブではなくスペースを使用していますが)、これにより、希望する出力が得られます。


それがまだ機能していないというあなたの主張に応えて、私は違うことを懇願しなければならないのではないかと心配しています。次のトランスクリプト(タブ付き)は、アドバタイズされたとおりに機能することを示しています。

pax> cat qq.in
Excellent   29      54      47      46      38      22      50
Good        7       14      27      24      26      36      20

pax> awk -F'\t' '{ for (i=2; i<=NF; i++) print $1 "\t" $i; }' qq.in
Excellent   29
Excellent   54
Excellent   47
Excellent   46
Excellent   38
Excellent   22
Excellent   50
Good        7
Good        14
Good        27
Good        24
Good        26
Good        36
Good        20

それが実際にご使用の環境で機能していない場合、それは別の問題です。バギーawkやその他の理由で失敗する可能性があります。

awkまず、次のように、使用しているオペレーティングシステムのバージョンとオペレーティングシステムを把握します。

awk --version
uname -a

(a):実際には何かを出力しますが、ほぼ確実に期待したものではありません。実際に何が起こっているのかを実際に見てみましょう。オリジナルに類似した次のトランスクリプトを検討してください。

pax> ( echo 1; echo 2; echo 3 ) | while read line ; do
...>     awk '{print "[" $0 "]"}'
...> done
[2]
[3]

今ではかなり奇妙に見えますが、最初の行を捨てているように見えます。

この理由は、whileとの間の切断awkです。はwhile、標準入力から最初の行を読み取り、それをに割り当ててから$line、セクションの本文を実行しdo..doneます。

その本体はawk入力ファイルがないため、標準入力から入力を受け取ります。

つまり、残りの標準入力ストリームを「吸い上げ」て処理します。

その後、ループに戻りwhileますが、標準入力のデータがなくなると、終了します。それはおそらく次のように説明したほうがよいでしょう。

pax> ( echo 1; echo 2; echo 3 ) | while read line ; do
...>     echo "read: $line"
...>     awk '{print "awk:  " $0}'
...> done
read: 1
awk:  2
awk:  3

とを以下のセクションに実際に接続するwhileと、正しく機能することがわかります。awkecho "$line" |

pax> ( echo 1; echo 2; echo 3 ) | while read line ; do
...>     echo "$line" | awk '{print "[" $0 "]"}'
...> done
[1]
[2]
[3]

もちろん、入力を1行に分割して、一度に1行に送信することはほとんど意味がありません。これは、複数の行を1つずつ完全に処理できるawk場合です。awk

したがって、awkこの回答の最初のコードブロックに示されている1行のコマンドは、それを実行するためのより良い方法です。

于 2012-10-09T00:35:34.677 に答える
2

できるよ

awk -F$'\t' '{ for (i=2; i<=NF; i++) print $1 "\t" $i "." }' FILE

すべての不要なパイプの代わりに。

于 2012-10-09T00:28:42.893 に答える