ディレクトリのテキストファイルブロックを1つ以上のファイルにマージする方法は?

ディレクトリのテキストファイルブロックを1つ以上のファイルにマージする方法は?

ディレクトリ内のテキストファイルの塊を1つ以上のファイルにマージしてから、マージされたファイルを圧縮する必要があります。

例:ディレクトリに500,000のテキストファイルがある場合は、Aと言います。 50,000個のファイルセットを1つのファイルセットにマージしたいと思います。つまり、それぞれ50,000個のファイルの内容を含む10個のマージされたファイルがあります。最後に、マージされた各ファイルを圧縮したいと思います。つまり、このプロセスが完了すると、合計10個のzipファイルがあります。

シェルスクリプトでこれを実行しようとしています。解決策が見つかりません。

誰かがシェルスクリプトを使用してこれを達成する最も効率的な方法を教えてください。

答え1

私のビューには多数のファイルを含むディレクトリが1つしかないので、ファイルリストをリンクするのではなく小さなファイルセットに分割し、必要に応じて小さなファイルを圧縮して削除する必要があります。

私が提案できる方法は次のとおりです。

cd /to/dir/with/many/files/
mkdir ../tmp
find . | split -l 50000 ../tmp/x
for i in ../tmp/x* ; do 
    while read filename ; do
        cat "$filename" >> "${i}.text" ;
        # rm "$filename" # uncomment it only if you need to delete small files
    done <"$i"
    zip "${i}.zip"  "${i}.text"
    # rm "${i}.text" # uncomment it only if you need to delete result file
done

答え2

これには2つの回避策があります。 1つはnファイルを1つのアーカイブに追加すること、もう1つは最初にすべてのファイルをリンクしてから圧縮することです。

両方の方法の一般的なステップは次のとおりです。

# Generate a list of files to be zipped
find . -type f > filelist

# Loop to process n files stepwise
n=50000
fileno=1

for i in $(seq 1 $n $(wc -l < filelist)); do
  # compression code goes here, see below
done

ファイルを個別に圧縮

# automatic name generation
zipfile=$(printf "%04d" $((fileno++)))

# extract lines $i to $i+$n-1 from filelist 
sed -n "$i,$((i+n-1))p" filelist | zip $zipfile -@

接続と圧縮

(および他のコンプレッサー)を使用してこれを行うにはgzip非常に簡単です。

zipfile=$(printf "%04d" $((fileno++)))
sed -n "$i,$((i+n-1))p" filelist | xargs cat | gzip > $zipfile.gz

このモードはサポートされていないためzip(少なくとも私が持っているモードではない)、他のアプローチが必要です。zip名前付きパイプ(-FI)がサポートされています。ここで、アーカイブ内のファイルは名前付きパイプの名前を取得するため、ループ内で次の操作を実行すると機能します。

zipfile=$(printf "%04d" $((fileno++)))
mkfifo $zipfile
zip -FI $zipfile $zipfile &
sed -n "$i,$((i+n-1))p" filelist | xargs cat > $zipfile
rm $zipfile

関連情報