最初の列にファイルを分割する:開いているファイルが多すぎます。

最初の列にファイルを分割する:開いているファイルが多すぎます。

これは質問の拡張です。最初の列の値に基づいてファイルを複数のファイルに分割する。今すぐ参加したので、上記の質問にコメントを追加するのに十分な担当者ポイントがありません。だから何度もお詫び申し上げます。

次のコマンドを使用してファイルを最初の列に分割しました。

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 >filenameinを使用すると、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
    }

おすすめ記事