ファイルを抽出してさまざまなファイルを作成し、名前を変更します。

ファイルを抽出してさまざまなファイルを作成し、名前を変更します。

次の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番目のカンマ区切りフィールドが最初のフィールドで指定されたファイル名で印刷されます。NR1(これまで読み取ったレコード数)をテストして最初の行をスキップします。

これはシェルループと同じ問題を経験しません。出力ファイルは、最初のファイルの後に切り捨てられ(空になるか作成されます)、その後の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 を表示するたびに、出力ファイルを開いたり閉じたりする必要がないように、まずソートを実行します。

関連情報