GNU/Linux >> Linux の 問題 >  >> Linux

巨大なフォルダーのマルチ tar アーカイブを作成する方法

それを行うためにこのbashスクリプトを書きました。基本的に、各tarに入るファイルの名前を含む配列を形成し、tarを開始します それらすべてで並行して .これは最も効率的な方法ではないかもしれませんが、思い通りに作業を完了できます.ただし、大量のメモリを消費することが予想されます.

スクリプトの開始時にオプションを調整する必要があります。また、tar オプション cvjf を変更することもできます。 最後の行で (詳細な出力 v を削除するなど) パフォーマンスまたは圧縮の変更 j z まで など...).

スクリプト

#!/bin/bash

# User configuratoin
#===================
files=(*.log)           # Set the file pattern to be used, e.g. (*.txt) or (*)
num_files_per_tar=5 # Number of files per tar
num_procs=4         # Number of tar processes to start
tar_file_dir='/tmp' # Tar files dir
tar_file_name_prefix='tar' # prefix for tar file names
tar_file_name="$tar_file_dir/$tar_file_name_prefix"

# Main algorithm
#===============
num_tars=$((${#files[@]}/num_files_per_tar))  # the number of tar files to create
tar_files=()  # will hold the names of files for each tar

tar_start=0 # gets update where each tar starts
# Loop over the files adding their names to be tared
for i in `seq 0 $((num_tars-1))`
do
  tar_files[$i]="$tar_file_name$i.tar.bz2 ${files[@]:tar_start:num_files_per_tar}"
  tar_start=$((tar_start+num_files_per_tar))
done

# Start tar in parallel for each of the strings we just constructed
printf '%s\n' "${tar_files[@]}" | xargs -n$((num_files_per_tar+1)) -P$num_procs tar cjvf

説明

まず、選択したパターンに一致するすべてのファイル名が配列 files に格納されます .次に、for ループがこの配列をスライスし、スライスから文字列を形成します。スライスの数は、必要な tarball の数と同じです。結果の文字列は配列 tar_files に格納されます . for ループは、結果の tarball の名前も各文字列の先頭に追加します。 tar_files の要素 次の形式を取ります (5 ファイル/tarball を想定):

tar_files[0]="tar0.tar.bz2  file1 file2 file3 file4 file5"
tar_files[1]="tar1.tar.bz2  file6 file7 file8 file9 file10"
...

スクリプトの最後の行 xargs 複数の tar を開始するために使用されます それぞれが tar_files の 1 つの要素を処理するプロセス (指定された最大数まで) 並列に配列します。

テスト

ファイルのリスト:

$ls

a      c      e      g      i      k      m      n      p      r      t
b      d      f      h      j      l      o      q      s

生成された tarball:$ls /tmp/tar*tar0.tar.bz2 tar1.tar.bz2 tar2.tar.bz2 tar3.tar.bz2


ここに別のスクリプトがあります。セグメントごとに正確に 100 万個のファイルが必要か、正確に 30 個のセグメントが必要かを選択できます。このスクリプトでは前者を使用しましたが、split は キーワードでどちらかを選択できます。

#!/bin/bash
#
DIR="$1"        # The source of the millions of files
TARDEST="$2"    # Where the tarballs should be placed

# Create the million-file segments
rm -f /tmp/chunk.*
find "$DIR" -type f | split -l 1000000 - /tmp/chunk.

# Create corresponding tarballs
for CHUNK in $(cd /tmp && echo chunk.*)
do
    test -f "$CHUNK" || continue

    echo "Creating tarball for chunk '$CHUNK'" >&2
    tar cTf "/tmp/$CHUNK" "$TARDEST/$CHUNK.tar"
    rm -f "/tmp/$CHUNK"
done

このスクリプトに適用できる便利な機能がいくつかあります。 /tmp/chunk. の使用 ファイルリストのプレフィックスはおそらく定数宣言にプッシュする必要があり、コードは /tmp/chunk.* に一致するものをすべて削除できると実際に想定すべきではないためです。 、しかし、洗練されたユーティリティではなく、概念実証としてこの方法を残しました。これを使用する場合、mktemp を使用します ファイル リストを保持するための一時ディレクトリを作成します。


これは要求されたことを正確に実行します:

#!/bin/bash
ctr=0;
# Read 1M lines, strip newline chars, put the results into an array named "asdf"
while readarray -n 1000000 -t asdf; do
  ctr=$((${ctr}+1));
# "${asdf[@]}" expands each entry in the array such that any special characters in
# the filename won't cause problems
  tar czf /destination/path/asdf.${ctr}.tgz "${asdf[@]}";
# If you don't want compression, use this instead:
  #tar cf /destination/path/asdf.${ctr}.tar "${asdf[@]}";
# this is the canonical way to generate output
# for consumption by read/readarray in bash
done <(find /source/path -not -type d);

readarray (bash で) コールバック関数を実行するためにも使用できるため、次のように書き換えられる可能性があります:

function something() {...}
find /source/path -not -type d \
  | readarray -n 1000000 -t -C something asdf

GNU parallel 同様のことを行うために活用できます(テストされていません; parallel はありません 私がいる場所にインストールされているので、翼を広げています):

find /source/path -not -type d -print0 \
  | parallel -j4 -d '\0' -N1000000 tar czf '/destination/path/thing_backup.{#}.tgz'

それはテストされていないので、 --dry-run を追加できます arg を実行して、実際に何を行うかを確認します。私はこれが一番好きですが、誰もが parallel を持っているわけではありません インストールされています。 -j4 一度に 4 つのジョブ、-d '\0' を使用します。 find と組み合わせる の -print0 ファイル名の特殊文字 (空白など) を無視します。残りは一目瞭然です。

parallel でも同様のことができます しかし、ランダムなファイル名を生成するので、私はそれが好きではありません:

find /source/path -not -type d -print0 \
  | parallel -j4 -d '\0' -N1000000 --tmpdir /destination/path --files tar cz

[まだ?] シーケンシャルなファイル名を生成する方法を知りません。

xargs も使用できますが、parallel とは異なります 出力ファイル名を生成する簡単な方法はないため、次のようなばかげた/ハッキーなことをすることになります:

find /source/path -not -type d -print0 \
  | xargs -P 4 -0 -L 1000000 bash -euc 'tar czf $(mktemp --suffix=".tgz" /destination/path/backup_XXX) "[email protected]"'

OPは、スプリットを使用したくないと言っていました... cat として奇妙に思えると思いました それらをうまく再結合します。これにより tar が生成され、3 GB のチャンクに分割されます:

tar c /source/path | split -b $((3*1024*1024*1024)) - /destination/path/thing.tar.

...そして、これはそれらを現在のディレクトリに解凍します:

cat $(\ls -1 /destination/path/thing.tar.* | sort) | tar x

Linux
  1. 既存のSSL用のpemを作成する方法

  2. tar の絶対パスを除外するにはどうすればよいですか?

  3. .Trash-1000 フォルダの作成を無効にする方法は?

  1. Linux用のPythonアプリケーションをパッケージ化する方法

  2. Linuxですべてのユーザーの共有ディレクトリを作成する方法

  3. 別のユーザーの ssh キーを作成するにはどうすればよいですか?

  1. OpenStack用のWindowsイメージを作成する方法

  2. 隠しファイルを除いて、ディレクトリのtarアーカイブを作成しますか?

  3. Linux cpio の例:cpio アーカイブ (および tar アーカイブ) を作成および抽出する方法