GNU/Linux >> LINUX-Kenntnisse >  >> Linux

wie man Multi-Tar-Archive für einen riesigen Ordner erstellt

Ich habe dazu dieses Bash-Skript geschrieben. Es bildet im Grunde ein Array, das die Namen der Dateien enthält, die in jedes tar gehen, und startet dann tar parallel auf allen .Es ist vielleicht nicht der effizienteste Weg, aber es wird die Arbeit so erledigen, wie Sie es möchten.Ich kann jedoch davon ausgehen, dass es große Mengen an Speicher verbraucht.

Sie müssen die Optionen am Anfang des Skripts anpassen. Möglicherweise möchten Sie auch die Tar-Optionen cvjf ändern in der letzten Zeile (wie das Entfernen der ausführlichen Ausgabe v für Leistung oder Änderung der Komprimierung j bis z , etc ...).

Skript

#!/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

Erklärung

Zunächst werden alle Dateinamen, die dem ausgewählten Muster entsprechen, im Array files gespeichert . Als nächstes zerlegt die for-Schleife dieses Array und bildet Strings aus den Slices. Die Anzahl der Slices ist gleich der Anzahl der gewünschten Tarballs. Die resultierenden Strings werden im Array tar_files gespeichert . Die for-Schleife fügt außerdem den Namen des resultierenden Tarballs am Anfang jeder Zeichenfolge hinzu. Die Elemente von tar_files folgende Form annehmen (unter der Annahme von 5 Dateien/Tarball):

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

Die letzte Zeile des Skripts, xargs wird verwendet, um mehrere tar zu starten verarbeitet (bis zur maximal angegebenen Anzahl), wobei jeder ein Element von tar_files verarbeitet Array parallel.

Test

Liste der Dateien:

$ls

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

Generierte Tarballs:$ls /tmp/tar*tar0.tar.bz2 tar1.tar.bz2 tar2.tar.bz2 tar3.tar.bz2


Hier ist ein weiteres Skript. Sie können wählen, ob Sie genau eine Million Dateien pro Segment oder genau 30 Segmente möchten. Ich habe mich in diesem Skript für Ersteres entschieden, aber für split Schlüsselwort lässt beide Möglichkeiten zu.

#!/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

Es gibt eine Reihe von Feinheiten, die auf dieses Skript angewendet werden könnten. Die Verwendung von /tmp/chunk. da das Präfix der Dateiliste wahrscheinlich in eine konstante Deklaration verschoben werden sollte und der Code nicht wirklich davon ausgehen sollte, dass er alles löschen kann, was /tmp/chunk.* entspricht , aber ich habe es so belassen, eher als Machbarkeitsnachweis als als ausgefeiltes Dienstprogramm. Wenn ich dies verwenden würde, würde ich mktemp verwenden um ein temporäres Verzeichnis für die Dateilisten zu erstellen.


Dieser tut genau das, was angefordert wurde:

#!/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 (in bash) kann auch verwendet werden, um eine Callback-Funktion auszuführen, sodass sie möglicherweise so umgeschrieben werden könnte, dass sie aussieht:

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

GNU parallel könnte genutzt werden, um etwas Ähnliches zu tun (ungetestet; ich habe parallel nicht installiert, wo ich gerade bin, also beflügele ich es):

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

Da dies ungetestet ist, könnten Sie den --dry-run hinzufügen arg, um zu sehen, was es tatsächlich tun wird. Das gefällt mir am besten, aber nicht jeder hat parallel Eingerichtet. -j4 lässt es 4 Jobs gleichzeitig verwenden, -d '\0' kombiniert mit find ist -print0 bewirkt, dass Sonderzeichen im Dateinamen (Leerzeichen usw.) ignoriert werden. Der Rest sollte selbsterklärend sein.

Etwas Ähnliches könnte mit parallel gemacht werden aber ich mag es nicht, weil es zufällige Dateinamen generiert:

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

Ich kenne [noch?] keinen Weg, um fortlaufende Dateinamen zu generieren.

xargs könnte auch verwendet werden, aber anders als parallel Es gibt keinen einfachen Weg, den Ausgabedateinamen zu generieren, sodass Sie am Ende etwas Dummes/Hackiges wie das Folgende tun würden:

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]"'

Das OP sagte, sie wollten Split nicht verwenden ... Ich fand das komisch als cat wird sich ihnen wieder anschließen; dies erzeugt ein Tar und teilt es in 3-GB-Stücke auf:

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

... und das entpackt sie in das aktuelle Verzeichnis:

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

Linux
  1. So packen Sie Python-Anwendungen für Linux

  2. So erstellen Sie ein Windows-Image für OpenStack

  3. Tar-Archiv eines Verzeichnisses erstellen, außer für versteckte Dateien?

  4. Linux-cpio-Beispiele:So erstellen und extrahieren Sie cpio-Archive (und tar-Archive)

  5. Wie schließe ich absolute Pfade für tar aus?

So erstellen Sie eine Sicherung mit dem tar-Befehl unter Linux

Tar-Befehl unter Linux (Archive erstellen und extrahieren)

So erstellen Sie eine Tar-Gz-Datei

So entpacken Sie tar bz2 xz gz-Archive unter Linux

So erstellen Sie eine Tar gz-Datei

So erstellen Sie einen Domänencontroller unter Linux für AD