入力(タブ区切りフィールド)

入力(タブ区切りフィールド)

列の数が異なるファイルをサブセットにし、出力に複数のファイルを作成する必要があります。ループでこれを実行しようとしていますが、イテレータは機能しません。

入力(タブ区切りフィールド)

abc 1  
aaa 1  
ccc 1  
asd 2  
sad 2  
aaf 3  

出力

ファイル1:

abc 1  
aaa 1  
ccc 1    

ファイル2:

asd 2  
sad 2

ファイル3:

aaf 3  

私のテストはこれですが、空のファイルだけを出力します。

for i in $(seq 1 3); do awk -F "\t" '{$2 == $i}' input  > cluster.$i.txt; done 

答え1

コードが失敗する理由は、スクリプト$i内でシェル変数を使用しようとしましたが、awk間違って実行したためです。一重引用符内のテキストは'...'シェルで文字通り処理されるため、$iシェル変数の値ではなく2文字で処理されます$i。また、比較をジョブとして実行しようとしています(つまり、行を印刷する暗黙のジョブがないことを意味します)。

値を渡すことができます。awk

awk -F $'\t' -v i="$i" '$2 == i' input > "cluster.$i.txt"

あるいは、各行をそれ自体の利点に従って処理し、awk完全に回避することもできます。

while read field index
do
    printf "%s\t%s\n" "$field" "$index" >> "cluster.$index.txt"
done < input

または、次をawk使用して同じことを実行できます。

awk '{ fname = "cluster." $2 ".txt"; print > fname }' input

答え2

$iシェル変数はawk式で内部的に参照されませんi。コマンドラインを使用して変数を渡し、-v i="$i"それをプレーンとして引用することができますi

{....}また、行動一つでもない模様; modeがtrueのprintときにデフォルトの動作()を実行したいようです。$2 == iだから

for i in $(seq 1 3); do 
  awk -F "\t" -v i="$i" '$2 == i' 
input  > cluster.$i.txt; done

ただし、インデックスごとに awk を 1 回呼び出す代わりに、次のことを検討することができます。

awk -F "\t" '{print > "cluster" $2 ".txt"}' input

入力を直接使用して$2出力ファイル名を設定します。

空白文字のフィールド分割を特に回避したくない場合は、-F "\t"awkがデフォルトのスペース区切り文字を削除して分割することを許可できます。

関連情報