これは質問の拡張です。最初の列の値に基づいてファイルを複数のファイルに分割する。今すぐ参加したので、上記の質問にコメントを追加するのに十分な担当者ポイントがありません。だから何度もお詫び申し上げます。
次のコマンドを使用してファイルを最初の列に分割しました。
awk -F"\t" '{print>"subfolder/"$1}' inputfile
しかし、私は一つを得ましたawk: cannot open for output (Too many open files)
。
その後、コマンドを次のように変更しました。
awk -F"\t" '{print>"subfolder/"$1}{close("subfolder/"$1)}' inputfile
。
ただし、ファイルを閉じるとゼロバイトの出力ファイルが生成されます。
答え1
print >filename
inを使用すると、awk
ファイルが開き、ファイルがある場合は長さが0に切り捨てられます。 awk
それではそうです。ファイルを開いたままにしてくださいプログラムが終わるまで。多くのファイルに対してこれを行うと、わかるようにリソース制限が発生します。
あなたがしなければならないことはclose(filename)
あなたの分け前ですclose("subfolder/"$1)
。$1
正しい値を維持しながらこれを行う必要があります。
しかし、これは次のことを意味します。次 print >
ファイルを開き、前の内容を切り捨てます。
この問題を解決するには、print >>
代わりにを使用してくださいprint >
。これでファイルが開きます。追加。
次の問題は、awk
プログラムを2番目に実行すると最初の実行結果が追加されることです。これは、プログラムを再実行する前に削除または名前変更する出力ファイルを構成する必要があることを意味します。
完全なスクリプトは次のとおりです。
#!/bin/sh
rm -rf subfolder # remove old output files
mkdir subfolder # and recreate output directory
awk -F '\t' '{ fname = "subfolder/" $1; print >>fname; close(fname) }' inputfile
データが最初の列でソートされている場合は、実際に次の操作が必要になるまでファイルを閉じない非常に小さな最適化の利点を享受できます。
awk -F '\t' '
fname != "subfolder/" $1 {
if (fname != "")
close(fname)
fname = "subfolder/" $1
}
{ print >>fname }' inputfile
入力が最初のフィールドでソートされている場合は、上記のようprint >>
に変更できます。print >
データがソートされていない場合でも、を使用すると、それらの間print >>
に出力ファイルを閉じてから再度開く必要がなく(遅くても)、同じ最初のフィールドを持つ複数の連続した行が同じファイルに書き込まれます。
Mosvyがコメントで指摘したように、、ファイル名に次の値を使用したい誘惑を感じることができます。合理的な盲目的に書く前に。
値に小文字または大文字の英数字(および下線)のみが含まれていることを明示的に確認することでこれを行うことができます。
awk -F '\t' '
fname != "subfolder/" $1 {
if (fname != "")
close(fname)
fname = "subfolder/" $1
if (fname ~ /[^a-zA-Z0-9_]/) {
print "Bad filename: " fname >"/dev/stderr"
exit(1)
}
}
{ print >>fname }' inputfile
彼はまた、出力ファイルへのリダイレクトを処理する代替方法を提案しました。彼はファイル名を関連付けられたハッシュのキーとして保存します。
{
if (names[fname]++)
print >>fname
else
print >fname
}