次のCSVファイル(最初の列と2番目の列は「、」で区切られています)があります。
Column1,Column2
4e,info1
4t,info2
45t,info3
3,info4
Column1からインポートしたファイル名とColumn2からインポートした内容を使用して、各行に1つずつ4つの異なるファイルをインポートしたいと思います。
私の予想結果は次のとおりです。
ファイル名1 =4e.smi
info1
ファイル名2 =4t.smi
info2
ファイル名3 =45t.smi
info3
ファイル名4 =3.smi
info4
私は2つの異なる変数(最初の列に関連する1つ、2番目の列に関連する変数)を作成し、その変数を使用して新しいファイルを生成できると思いました。すべての行に対してループでこれを行います。しかし、このコマンドラインを試しましたが、うまくいきません。
while IFS=',' read -r name smile; do write "$smile" "$name".smi; done < InputFIle.txt
誰でもこの問題を解決するのに役立ちますか?
ありがとうございます。
答え1
write
このコマンドが使用したいコマンドではないことを除いて、ループはほぼ正確です。代わりにprintf
リダイレクトと一緒に使用してください。また、最初の行をスキップすることを確認する必要があり、さまざまな方法でこれを実行できます。以下ではを使用していますが、tail -n +2
使用することもできますsed 1d
。
tail -n +2 InputFIle.txt |
while IFS=, read -r name string; do
printf '%s\n' "$string" >"$name".smi
done
これは、ファイル名が一度だけ記録されると仮定します。 2つ以上の行が最初の列に同じ値を持つように、後続の行はファイルにすでに書き込まれたデータを上書きします。だから>
あなたは>>
に追加する結果ファイル。コードを2回実行する場合(そうでない場合は出力に重複データが表示されます)、この変更のためにそのファイルをさらに削除する必要があります。
awk
潜在的により効率的なアプローチは、次のように使用することです。
awk -F, 'NR > 1 { print $2 >($1 ".smi") }' InputFIle.txt
これにより、2番目のカンマ区切りフィールドが最初のフィールドで指定されたファイル名で印刷されます。NR
1(これまで読み取ったレコード数)をテストして最初の行をスキップします。
これはシェルループと同じ問題を経験しません。出力ファイルは、最初のファイルの後に切り捨てられ(空になるか作成されます)、その後のprint
出力が追加されます。
一部の行にさらに多くのフィールドがある場合は、awk
最初のフィールドを除くすべてのフィールドを印刷するようにバリアントを変更する必要があります。
awk -F, 'NR > 1 { name = $1; sub("[^,]*,",""); print >(name ".smi") }' InputFIle.txt
これにより、最初のフィールドが別々の変数に保存され、次を使用して元のname
行からフィールドが削除されます。sub()
次に、残りの行をファイルに印刷します。
答え2
生成する出力ファイルの数に関係なく、tail + sort + awkを使用すると効率的に機能します。
tail -n +2 file | sort | awk -F, '$1!=prev{close(out); out=$1".smi"; prev=$1} {print $2 > out}'
出力ファイルを常に閉じていないと、ほとんどのawkで「開いたファイルが多すぎます」というエラーが発生したり、GNU awkがファイルの開閉を管理しようとするため、速度が大幅に遅くなります。超過すると、20個の出力ファイルのしきい値未満で表示されます。入力で重複した $1 を表示するたびに、出力ファイルを開いたり閉じたりする必要がないように、まずソートを実行します。