Pourquoi tous les fichiers ne sont-ils pas compressés et comment améliorer la solution

8

J'ai un dossier avec environ 20K fichiers. Les fichiers sont nommés selon le modèle xy_{\d1,5}_{\d4}\.abc, par exemple xy_12345_1234.abc. Je voulais compresser les premiers 10K d'entre eux en utilisant cette commande:

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

cependant, le fichier résultant ne contenait qu'environ 2 Ko de fichiers.

ls | sort -n -k1.4,1.9 | head -n10000 | wc -l renvoie cependant 10 000, comme prévu.

Il me semble que je comprends mal quelque chose de fondamental ici ...

J'utilise zsh 5.0.2 sous Linux Mint 17.1, GNU tar 1.27.1

ÉDITER:

la fourche telle que suggérée par @Archemar semble très plausible, la dernière fourchette écrasant le fichier résultant - le fichier contient la «queue» des fichiers - 7773 à 9999 .

résultat de 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

remplacer -cpar -rou -un'a pas fonctionné dans mon cas. Le message d'erreur étaittar: Cannot update compressed archives

en utilisant les deux -ret -un'est pas valide et échoue avectar: You may not specify more than one '-Acdtrux', '--delete' or '--test-label' option

le remplacement -cpar -asemble également invalide et échoue avec le même tar: You must specify one of the '-Acdtrux', '--delete' or '--test-label' optionssi je ne reconnais pas le problème azfet Acdtruxme semble disjoint.

EDIT 2:

-T ressemble à un bon moyen, j'ai également trouvé un exemple ici .

Mais quand j'essaye

ls | sort -n -k1.4,1.9 | head -n10000 | tar -czf xy_0_10000.tar.gz -T - Je reçois tar: option requires an argument -- 'T'

bien, peut-être que les noms de fichiers n'atteignent pas tar? Mais on dirait qu'ils le font parce que quand j'exécute

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

Alors pourquoi tar ne voit-il pas les noms de fichiers?

kostja
la source
et si vous essayez un au lieu de c, dans la commande tar?
Olivier Dulac
5
Pertinent: ne pas analyser la sortie dels
8bittree
1
Le fichier OP n'a pas de noms délicats.
Archemar
@ 8bittree - ainsi qu'un conseil général pour des scripts shell robustes, oui. mais que proposez-vous à la place pour travailler avec des listes de fichiers avec les oneliners ponctuels habituels?
kostja
1
@kostja que j'utiliserais find, qui a une -print0option pour utiliser un octet nul comme délimiteur au lieu d'une nouvelle ligne. sortpeut gérer cela avec le -zdrapeau. head, malheureusement, ne gère pas les séparateurs d'octets nuls, mais cette réponse a une solution en utilisant trpour permuter \net \0avant et après head. tardoit --null -T -lire les noms de fichiers séparés par des valeurs nulles stdin.
8bittree

Réponses:

12

vous avez atteint la limite xargs?

xargs --show-limit

essayez:

  • créer un .tgzfichier facticetar czf xy_0_10000.tar.gz /hello/world
  • remplacer -czfpar -Azf

quand xarg a atteint sa limite, il exécutera la commande, donc la commande que vous avez exécutée ultimement était

  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

comme chaque goudron remplace le précédent, vous ne devriez obtenir que la dernière tar cexécution.

Éditer:

1) selon man tarsur unbuntu, -aet -r semble que l' ajout équivalent soit fait par (soit) -A, --catenate, --concatenate

2) zip(pas gzip) peut être utilisé pour ajouter un fichier, peut-être qu'une option gzip fera l'affaire. (utilisez | xargs zip -qr xy_0_0000.zip, cela se traduira par un fichier zip, pas un .tar.gz cependant)

3) pour utiliser la solution de @ rsanchez
Il est important d'ajouter correctement l'option tar à tar, essayez

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

où - -T -signifie utiliser l'option -Tet l'utiliser -comme argument -T(vous auriez pu générer une liste de fichiers dans /tmp/foo.lst, puis utiliser -T /tmp/foo.lst)

Archemar
la source
un (= ajouter) au lieu de c (= créer / écraser) pourrait-il contourner cette limitation?
Olivier Dulac
@OlivierDulac ( Attention: c'est une pure supposition ) Cela ne résoudra probablement pas car tar ne peut pas créer de fichiers vides. Vous pouvez d'abord compresser un dossier vide et utiliser a (add)pour ajouter les fichiers au fichier tar. Ensuite, vous pouvez ouvrir le tar et supprimer le dossier (en utilisant 7zip ou quelque chose)
Ismael Miguel
@ismaelmiguel: Je suis à peu près sûr qu'il créera avec plaisir le fichier. sinon, juste:touch xy_0_10000.tar.gz && { _the full command here_ ; }
Olivier Dulac
1
@OlivierDulac Ce sera un .gzfichier invalide .
Ismael Miguel du
Toutes les pages de manuel que je vois sur manpages.ubuntu.com/manpages/vivid/en/man1/tar.1.html (15.04) pour revenir à la précision (12.04) ont un -rajout mais une -acompression automatique qui n'est pas équivalente. Et -rzne fonctionne pas: zippeut s'ajouter à une archive existante car le répertoire n'est pas compressé, mais taravec la compression, il compresse les métadonnées avec les données. Vous pouvez tar -rpar morceaux dans une archive non compressée , puis compresser le résultat. Ou ...
dave_thompson_085
12

Ce n'est pas nécessaire xargs. Si vous donnez directement tarl' -T -option, il lira les noms de fichiers à partir de l'entrée standard.

Par exemple:

... | tar -T - -czf xy_0_10000.tar.gz
rsanchez
la source
Il semble que j'utilise mal l'option, je ne peux pas la faire fonctionner avec le tuyau. Ont essayé ...| tar Tczf xy_..., ...| tar Tcz -f xy_... ...| tar -czf xy_... -T et plusieurs autres permutations, mais je suis obtient que tar: You must specify one of the '-Acdtrux', '--delete' or '--test-label' options, tar: -f: Cannot stat: No such file or directorysi vous utilisez -fséparément des autres options et tar: option requires an argument -- 'T'. Pourriez-vous s'il vous plaît ajouter un exemple d'utilisation?
kostja
Exemple de @kostja ajouté.
rsanchez
Merci beaucoup, rsanchez. Vous ne savez pas pourquoi la variante avec -T -à la fin de la tarliste d'options n'a pas fonctionné, mais votre exemple a fonctionné. Malheureusement, ma question comportait en fait deux parties - la source de l'erreur et une amélioration possible. Pendant que vous avez accédé à ce dernier, Archemar a excellé dans le premier et avait presque le dernier droit. Je ne sais pas laquelle de vos réponses accepter, car elles ont toutes deux été utiles.
kostja
1

Je veux compléter les deux autres réponses avec une solution zsh , qui n'analyse pas ls , ni n'a besoin de xargs . Cependant, je ne suis pas sûr pour l'instant, s'il souffre également de la limitation de la longueur de la ligne de commande.

  1. Définissez une fonction qui génère la clé de tri souhaitée en la modifiant $REPLY.

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

    Cela équivaut à votre sort -n -k1.4,1.9

  2. Générez un tableau $filesavec les noms de fichiers triés avec la fonction ci-dessus:

    files=(*(o+sortkey))

    Cela équivaut à ls | sort -n -k1.4,1.9

  3. Renvoyez les 10 000 premiers fichiers avec

    ${files[0,9999]}

    Cela équivaut à ls | sort -n -k1.4,1.9 | head -n10000

Donc, dans l'ensemble, cela devrait faire l'affaire:

sortkey() { REPLY=${REPLY[4,9]} }
files=(*(o+sortkey))
tar -czf xy_0_10000.tar.gz ${files[0,9999]}
mpy
la source