Suche nach einem Unix-Tool/-Skript, das bei einem angegebenen Eingabepfad jeden Stapel unkomprimierter 100 MB großer Textdateien in eine einzelne GZIP-Datei komprimiert

Suche nach einem Unix-Tool/-Skript, das bei einem angegebenen Eingabepfad jeden Stapel unkomprimierter 100 MB großer Textdateien in eine einzelne GZIP-Datei komprimiert

Ich habe einen Dump von Tausenden kleiner Textdateien (1-5 MB) mit jeweils mehreren Textzeilen. Ich muss sie „stapelweise“ zusammenfassen, sodass jeder Stapel eine feste Größe hat – sagen wir 100 MB – und diesen Stapel dann komprimieren.

Dieser Stapel könnte nun wie folgt aussehen:

  1. Eine einzelne Datei, die lediglich eine Zusammenfassung der Inhalte der einzelnen Textdateien ist, oder
  2. Nur die einzelnen Textdateien selbst

Vorbehalte:

  1. Unix split -bfunktioniert hier nicht, da ich Textzeilen intakt halten muss. Die Verwendung der linesOption ist etwas kompliziert, da die Anzahl der Bytes in jeder Zeile stark variiert.
  2. Die Dateien müssen nicht unbedingt eine feste Größe haben, solange sie innerhalb von 5 % der angeforderten Größe liegen
  3. Die Zeilen sind kritisch und sollten nicht verloren gehen: Ich muss bestätigen, dass die Eingabe ohne Verlust zur Ausgabe gelangt ist – welche rollierende Prüfsumme (so etwas wie CRC32, ABER besser/„stärker“ im Hinblick auf Kollisionen)

Ein Skript sollte das auch tun, aber das scheint eine Aufgabe zu sein, die schon jemand gemacht hat, und es wäre schön, Code zu sehen (vorzugsweise Python oder Ruby), der zumindest etwas Ähnliches kann.

Antwort1

Das folgende Skript erstellt komprimierte Dateipakete im angegebenen Verzeichnis. Sie rufen es wie folgt auf:

script.sh directorypath

Es verwendet einen einfachen/naiven Algorithmus (genau wie den, den Sie beschrieben haben):

  • Alle Dateien zählen.
  • Beginnen Sie mit dem rekursiven Lesen aller Dateien.
  • Holen Sie sich Größe, ls-Eintrag und Prüfsumme (SHA1) jeder Datei. (Speichern Sie den ls-Eintrag in manifest.txt und die Prüfsumme in checksum.txt.)
  • Wenn die Größe gerade das Limit überschritten hat, verwenden Sie die Liste „manifest.txt“, um eine komprimierte TAR-Datei zu erstellen (die auch die Manifest- und Prüfsummendateien enthält).
  • Erstellen Sie ein temporäres Verzeichnis und entpacken Sie die gerade erstellte TAR-Datei.
  • Berechnen Sie neue Prüfsummen der gerade extrahierten Dateien.
  • Vergleichen Sie mit gespeicherten Prüfsummen.
  • Wenn mindestens eine Prüfsumme unterschiedlich ist, beenden Sie das Programm mit einem Fehler.
  • Überprüfen Sie andernfalls, ob die Löschoption aktiviert ist. Wenn ja, entfernen Sie die Quelldateien.
  • Wiederholen Sie den Vorgang, bis keine Dateien mehr vorhanden sind.

Die Ausgabe sieht wie folgt aus:

Reading files...
15898 849 ../out/f068715p.jpg
Creating package (pack18.tar.gz) with 849 files, using 100078420 bytes...
tar: Removing leading `../' from member names
Preparing to verify package...
Creating new checksums...
Comparing checksums...
Package verification OK.
Deleting temporary verification directory...
Reading files...
16731 833 ../out/f069111c.jpg
Creating package (pack19.tar.gz) with 833 files, using 100004735 bytes...
tar: Removing leading `../' from member names
Preparing to verify package...
Creating new checksums...
Comparing checksums...
Package verification OK.
Deleting temporary verification directory...
Reading files...

Paketdateien werden im aktuellen Verzeichnis erstellt.

Eine Warnung:

  • Das aktuelle Verzeichnis und das Quellverzeichnis sollten weder über- noch untergeordnet noch unter- oder übergeordnet sein. Dies wurde nicht auf diese Weise getestet.

Dies ist das Skript (PACKSIZELIMIT ist die Anzahl der Bytes, wenn DELETESOURCE 1 ist, werden die Quelldateien gelöscht [Sie sollten auch das Symbol # vor der Zeile „rm -f“ entfernen]):

#!/bin/bash

PACKSIZELIMIT=100000000
PACKPREFFIX="pack"
#PACKSUFFIX=$(date +"_%Y%m%d_%H%M")
PACKSUFFIX=""
DELETESOURCE=0


LISTFILE="packbatchlist.txt"
MANIFESTFILE="manifest.txt"
CHECKSUMFILE="checksums.txt"
VERIFYFILE="verifysums.txt"



if [ -d "$1" ]; then
  PACKCOUNTER=0
  PACKSIZE=0
  FILECOUNTER=0
  ALLFILECOUNTER=0
  cat /dev/null > $LISTFILE
  cat /dev/null > $MANIFESTFILE
  cat /dev/null > $CHECKSUMFILE
  cat /dev/null > $VERIFYFILE
  echo "Reading files..."
  TOTALFILES=$(find "$1" -type f | wc -l)
  echo "There are $TOTALFILES files to process..."
  find "$1" -type f | while read SOURCEFILE ; do
    let "FILECOUNTER+=1"
    let "ALLFILECOUNTER+=1"
    echo -ne "\r$ALLFILECOUNTER $FILECOUNTER $SOURCEFILE\e[K"
    THISFILESIZE=$(stat -c %s "$SOURCEFILE")
    let "PACKSIZE+=$THISFILESIZE"
    echo $SOURCEFILE >> $LISTFILE
    ls -l $SOURCEFILE >> $MANIFESTFILE
    sha1sum $SOURCEFILE >> $CHECKSUMFILE
    if [ $PACKSIZE -gt $PACKSIZELIMIT -o $ALLFILECOUNTER -eq $TOTALFILES ]; then
      echo
      echo $MANIFESTFILE >> $LISTFILE
      echo $CHECKSUMFILE >> $LISTFILE
      PACKFILENAME="$PACKPREFFIX$PACKCOUNTER$PACKSUFFIX.tar.gz"
      echo "Creating package ($PACKFILENAME) with $FILECOUNTER files, using $PACKSIZE bytes..."
      tar -cf - -T $LISTFILE | gzip -c > $PACKFILENAME
      echo "Preparing to verify package..."
      TEMPCHECKDIR=$(mktemp -d)
      tar xzf $PACKFILENAME -C $TEMPCHECKDIR
      if [ -r "$TEMPCHECKDIR/$CHECKSUMFILE" ] ; then
        cut -d " " -f 1 $TEMPCHECKDIR/$CHECKSUMFILE > $VERIFYFILE
        sort $VERIFYFILE > $TEMPCHECKDIR/$CHECKSUMFILE
        echo "Creating new checksums..."
        cat /dev/null > $VERIFYFILE
        find "$TEMPCHECKDIR" -type f | while read CHECKEDFILE ; do
          CHECKEDFILESHORT=$(basename $CHECKEDFILE)
          if [ "$CHECKEDFILESHORT" != "$MANIFESTFILE" -a "$CHECKEDFILESHORT" != "$CHECKSUMFILE" ] ; then
            sha1sum $CHECKEDFILE | cut -d " " -f 1 >> $VERIFYFILE
          fi
        done
        sort $VERIFYFILE -o $VERIFYFILE
        echo "Comparing checksums..."
        DIFFFILES=$(comm --nocheck-order -3 $TEMPCHECKDIR/$CHECKSUMFILE $VERIFYFILE | wc -l)
        if [ $DIFFFILES -gt 0 ] ; then
          echo "ERROR: Package failed verification!"
          exit 2
        else
          echo "Package verification OK."
          echo "Deleting temporary verification directory..."
          find "$TEMPCHECKDIR" -delete
          if [ "$DELETESOURCE" == "1" ] ; then
            echo "Deleting source files..."
            cat $LISTFILE | while read FILE2DEL ; do
              echo -ne "\rDeleting $FILE2DEL ... \e[K"
              #rm -f $FILE2DEL
            done
            echo -e "\rFiles deleted.\e[K"
          fi
        fi
      else
        echo "ERROR: Cannot find checksum file from package!"
        exit 1
      fi
      let "PACKCOUNTER+=1"
      PACKSIZE=0
      FILECOUNTER=0
      cat /dev/null > $LISTFILE
      cat /dev/null > $MANIFESTFILE
      cat /dev/null > $CHECKSUMFILE
      cat /dev/null > $VERIFYFILE
      echo "Reading files..."
    fi
  done
else 
  echo
  echo "Missing source directory"
  echo
fi   


rm -f $LISTFILE
rm -f $MANIFESTFILE
rm -f $CHECKSUMFILE
rm -f $VERIFYFILE

Antwort2

GNU Split verfügt über eine -COption, die ähnlich ist, -bZeilen aber nicht umbricht.

verwandte Informationen