Warum werden nicht alle Dateien komprimiert und wie kann die Lösung verbessert werden?


8

Ich habe einen Ordner mit ca. 20K Dateien. Die Dateien werden nach dem Muster benannt xy_{\d1,5}_{\d4}\.abc, z xy_12345_1234.abc. Ich wollte die ersten 10 KB mit diesem Befehl komprimieren:

ls | sort -n -k1.4,1.9 | head -n10000 | xargs tar -czf xy_0_10000.tar.gz

Die resultierende Datei enthielt jedoch nur etwa 2K-Dateien.

ls | sort -n -k1.4,1.9 | head -n10000 | wc -l Gibt jedoch erwartungsgemäß 10000 zurück.

Es scheint mir, dass ich hier etwas Grundlegendes falsch verstehe ...

Ich verwende zsh 5.0.2 unter Linux Mint 17.1, GNU tar 1.27.1

BEARBEITEN:

Das von @Archemar vorgeschlagene Forking klingt sehr plausibel, wobei die neueste Fork die resultierende Datei überschreibt - die Datei enthält den 'Schwanz' der Dateien - 7773 bis 9999 .

Ergebnis von xargs --show-limit: Your environment variables take up 3973 bytes POSIX upper limit on argument length (this system): 2091131 POSIX smallest allowable upper limit on argument length (all systems): 4096 Maximum length of command we could actually use: 2087158 Size of command buffer we are actually using: 131072

Ersetzen -cdurch -roder -uhat in meinem Fall nicht funktioniert. Die Fehlermeldung wartar: Cannot update compressed archives

mit beiden -rund -uist ungültig und schlägt fehl mittar: You may not specify more than one '-Acdtrux', '--delete' or '--test-label' option

Das Ersetzen -cdurch -ascheint ebenfalls ungültig zu sein und schlägt damit fehl, tar: You must specify one of the '-Acdtrux', '--delete' or '--test-label' optionsobwohl ich das Problem nicht erkenne azfund Acdtruxmir unzusammenhängend vorkomme.

EDIT 2:

-T sieht nach einem guten Weg aus, ich habe hier auch ein Beispiel gefunden .

Jedoch wenn ich es versuche

ls | sort -n -k1.4,1.9 | head -n10000 | tar -czf xy_0_10000.tar.gz -T - Ich bekomme tar: option requires an argument -- 'T'

Nun, vielleicht erreichen die Dateinamen nicht Teer? Aber es sieht so aus, als ob sie es tun, wenn ich es ausführe

ls | sort -n -k1.4,1.9 | head -n10000 | tar --null -czf xy_0_10000.tar.gz -T - Ich bekomme tar: xy_0_.ab\nxy_1_...<the rest of filenames separated by literal \n>...998.ab Cannot stat: File name too long

Warum sieht Teer die Dateinamen nicht?


und wenn Sie a anstelle von c versuchen, im Befehl tar?
Olivier Dulac

5
Relevant: ls
Analysieren

1
OPs Datei hat keine kniffligen Namen.
Archemar

@ 8bittree - sowie ein allgemeiner Rat für robuste Shell-Skripte, ja. Aber was schlagen Sie stattdessen für die Arbeit mit Dateilisten mit den regulären einmaligen Onelinern vor?
Kostja

1
@kostja Ich würde verwenden find, die die -print0Option hat, ein Null-Byte als Trennzeichen anstelle eines Zeilenumbruchs zu verwenden. sortkann das mit der -zFlagge behandeln. head, leider nicht verstehen verstehen Null-Byte-Trennzeichen, aber diese Antwort hat eine Lösung mit trSwap \nund \0vor und nach head. tarmuss --null -T -null getrennte Dateinamen von lesen stdin.
8bittree

Antworten:


12

Du hast das Xargs-Limit erreicht?

xargs --show-limit

Versuchen :

  • Erstellen Sie eine Dummy- .tgzDateitar czf xy_0_10000.tar.gz /hello/world
  • ersetzen -czfdurch -Azf

Wenn xarg sein Limit erreicht hat, wird es den Befehl geben, also war der Befehl, den Sie letztendlich ausgeführt haben, der Befehl

  tar czf xy_0_10000.tar.gz file1 file2 .... file666
  tar czf xy_0_10000.tar.gz file667 file668 ... file1203
  tar czf xy_0_10000.tar.gz file1024 ... file2000

Da jeder Teer den vorherigen überschreibt, sollten Sie nur den letzten tar cLauf erhalten.

Bearbeiten:

1) nach man taron unbuntu, -aund -r scheint gleichwertig zu sein, wird angehängt von (entweder) -A, --catenate, --concatenate

2) zip(nicht gzip) kann zum Hinzufügen von Dateien verwendet werden, möglicherweise reicht eine gzip-Option aus. (Verwenden Sie | xargs zip -qr xy_0_0000.zip, dies führt zu einer Zip-Datei, jedoch nicht zu einer .tar.gz)

3) um die Lösung von @ rsanchez zu verwenden
Es ist wichtig, die Option tar ordnungsgemäß hinzuzufügen, versuchen Sie es

ls | sort -n -k1.4,1.9 | head -n10000 |tar -czf xy_0_10000.tar.gz -T -

where - -T -mean use option -Tund use -als Argument für -T(Sie könnten eine Liste von Dateien in generieren /tmp/foo.lstund dann verwenden -T /tmp/foo.lst)


Könnte a (= add) anstelle von c (= create / overwrite) diese Einschränkung umgehen?
Olivier Dulac

@OlivierDulac ( Warnung: Dies ist eine reine Vermutung ) Es wird wahrscheinlich nicht gelöst, da tar keine leeren Dateien erstellen kann. Sie können zuerst einen leeren Ordner komprimieren und a (add)die Dateien zur TAR-Datei hinzufügen. Dann können Sie den Teer öffnen und den Ordner entfernen (mit 7zip oder etwas)
Ismael Miguel

@ismaelmiguel: Ich bin mir ziemlich sicher, dass es die Datei glücklich erstellen wird. wenn nicht, nur:touch xy_0_10000.tar.gz && { _the full command here_ ; }
Olivier Dulac

1
@OlivierDulac Das ist eine ungültige .gzDatei.
Ismael Miguel

Alle Manpages, die ich von manpages.ubuntu.com/manpages/vivid/en/man1/tar.1.html (15.04) bis zu präzise (12.04) sehe, haben -rAnhängen, aber eine -aautomatische Komprimierung, die nicht gleichwertig ist. Und -rzfunktioniert nicht: zipKann zu einem vorhandenen Archiv hinzugefügt werden, da das Verzeichnis nicht komprimiert ist, aber tarbei der Komprimierung werden die Metataten zusammen mit den Daten komprimiert. Sie können tar -rstückweise in ein unkomprimiertes Archiv gehen und dann das Ergebnis gzipen. Oder ...
dave_thompson_085

12

Es besteht keine Notwendigkeit für xargs. Wenn Sie tardie -T -Option direkt angeben, werden die Dateinamen von der Standardeingabe gelesen .

Zum Beispiel:

... | tar -T - -czf xy_0_10000.tar.gz

Ich scheine die Option falsch zu verwenden, kann sie nicht mit der Pipe zum Laufen bringen. Habe versucht ...| tar Tczf xy_..., ...| tar Tcz -f xy_... ...| tar -czf xy_... -T und mehrere andere Permutationen, bekomme aber nur tar: You must specify one of the '-Acdtrux', '--delete' or '--test-label' options, tar: -f: Cannot stat: No such file or directorywenn -fgetrennt von anderen Optionen und verwendet tar: option requires an argument -- 'T'. Könnten Sie bitte ein Verwendungsbeispiel hinzufügen?
Kostja

@ kostja Beispiel hinzugefügt.
Rsanchez

Vielen Dank, rsanchez. Ich bin mir nicht sicher, warum die Variante mit -T -am Ende der tarOptionsliste nicht funktioniert hat, aber Ihr Beispiel hat funktioniert. Leider bestand meine Frage tatsächlich aus zwei Teilen - der Fehlerquelle und einer möglichen Verbesserung. Während Sie Letzteres übertrafen, war Archemar bei Ersterem überragend und hatte beinahe das letztere Recht. Ich bin mir nicht sicher, welche Ihrer Antworten Sie akzeptieren sollen, da beide offensichtlich hilfreich waren.
Kostja

1

Ich möchte die beiden anderen Antworten mit einer zsh- Lösung ergänzen , die weder ls analysiert noch xargs benötigt . Ich bin mir derzeit jedoch nicht sicher, ob es auch unter der Begrenzung der Kommandozeilenlänge leidet.

  1. Definieren Sie eine Funktion, die durch Ändern den gewünschten Sortierschlüssel generiert $REPLY.

    sortkey() { REPLY=${REPLY[4,9]} }

    Dies entspricht Ihrem sort -n -k1.4,1.9

  2. Generieren Sie ein Array $filesmit den Dateinamen, sortiert nach der obigen Funktion:

    files=(*(o+sortkey))

    Dies entspricht ls | sort -n -k1.4,1.9

  3. Geben Sie die ersten 10 000 Dateien mit zurück

    ${files[0,9999]}

    Dies entspricht ls | sort -n -k1.4,1.9 | head -n10000

Alles in allem sollte dies also den Trick tun:

sortkey() { REPLY=${REPLY[4,9]} }
files=(*(o+sortkey))
tar -czf xy_0_10000.tar.gz ${files[0,9999]}
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.