Perché non tutti i file sono compressi e come migliorare la soluzione


8

Ho una cartella con circa 20K file. I file vengono denominati in base al modello xy_{\d1,5}_{\d4}\.abc, ad es xy_12345_1234.abc. Volevo comprimere i primi 10K usando questo comando:

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

tuttavia il file risultante conteneva solo circa 2K file all'interno.

ls | sort -n -k1.4,1.9 | head -n10000 | wc -l tuttavia restituisce 10000, come previsto.

Mi sembra di aver frainteso qualcosa di semplice qui ...

Sto usando zsh 5.0.2 su Linux Mint 17.1, GNU tar 1.27.1

MODIFICARE:

il fork come suggerito da @Archemar sembra molto plausibile, con l'ultimo fork che sovrascrive il file risultante - il file contiene la 'coda' dei file - da 7773 a 9999 .

risultato di 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

la sostituzione -ccon -ro -unon ha funzionato nel mio caso. Il messaggio di errore eratar: Cannot update compressed archives

usando entrambi -re -unon è valido e falliscetar: You may not specify more than one '-Acdtrux', '--delete' or '--test-label' option

anche la sostituzione -ccon -asembra non essere valida e fallisce con lo stesso tar: You must specify one of the '-Acdtrux', '--delete' or '--test-label' optionsanche se non riconosco il problema azfe Acdtruxmi sembra disgiunto.

MODIFICA 2:

-T sembra un buon modo, ho anche trovato un esempio qui .

Comunque quando ci provo

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

bene, forse i nomi dei file non raggiungono il catrame? Ma sembra che lo facciano perché quando eseguo

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

Allora perché tar non vede i nomi dei file?


e se provi a invece di c, nel comando tar?
Olivier Dulac il


1
Il file OP non ha nomi complicati.
Archemar,

@ 8bittree - oltre a un consiglio generale per script di shell robusti, sì. ma cosa suggerisci invece di lavorare con liste di file con i normali oneliner una tantum?
kostja,

1
@kostja Vorrei usare find, che ha -print0un'opzione per usare un byte null come delimitatore invece di una nuova riga. sortposso gestirlo con la -zbandiera. head, sfortunatamente non gestisce capire i delimitatori di byte nulli, ma questa risposta ha una soluzione che usa trper scambiare \ne \0prima e dopo head. tardeve --null -T -leggere i nomi di file delimitati da null da stdin.
8

Risposte:


12

hai raggiunto il limite di xargs?

xargs --show-limit

provare :

  • creare un .tgzfile fittiziotar czf xy_0_10000.tar.gz /hello/world
  • sostituire -czfcon -Azf

quando xarg raggiunge il suo limite, eseguirà il comando fork, quindi il comando che hai eseguito alla fine lo è stato

  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

poiché ogni tar ha la precedenza su quello precedente, si potrebbe ottenere solo l'ultima tar ccorsa.

Modificare:

1) secondo man tarunbuntu, -ae -r sembra che un'appendice equivalente sia fatta da (o) -A, --catenate, --concatenate

2) zip(no gzip) può essere usato per aggiungere file, forse un'opzione gzip farà il trucco. (usare | xargs zip -qr xy_0_0000.zip, questo comporterà un file zip, non un .tar.gz comunque)

3) utilizzare la soluzione di @ rsanchez
È importante aggiungere un'opzione per tar in modo corretto, provare

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

dove - -T -indica l'opzione use -Te usa -come argomento per -T(potresti aver generato un elenco di file in /tmp/foo.lst, quindi usare -T /tmp/foo.lst)


potrebbe un (= aggiungere) invece di c (= creare / sovrascrivere) aggirare quella limitazione?
Olivier Dulac il

@OlivierDulac ( Attenzione: questa è una supposizione pura ) Probabilmente non risolverà poiché tar non può creare file vuoti. È possibile comprimere prima una cartella vuota e utilizzare a (add)per aggiungere i file al file tar. Quindi, puoi aprire il tar e rimuovere la cartella (usando 7zip o qualcosa del genere)
Ismael Miguel,

@ismaelmiguel: Sono abbastanza sicuro che creerà felicemente il file. in caso contrario, solo:touch xy_0_10000.tar.gz && { _the full command here_ ; }
Olivier Dulac il

1
@OlivierDulac Questo sarà un .gzfile non valido .
Ismael Miguel,

Tutte le manpage che vedo da manpages.ubuntu.com/manpages/vivid/en/man1/tar.1.html (15.04) indietro a precise (12.04) hanno -rappend ma -aauto-compress che non è equivalente. E -rznon funziona: zippuò essere aggiunto a un archivio esistente perché la directory non è compressa, ma tarcon la compressione comprime i metatdata insieme ai dati. È possibile inserire a tar -rtratti un archivio non compresso e quindi decomprimere il risultato. Oppure ...
dave_thompson_085 il

12

Non ce n'è bisogno xargs. Se dai direttamente tarl' -T -opzione leggerà i nomi dei file dallo standard input.

Per esempio:

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

Sembra che stia usando l'opzione in modo errato, non riesco a farlo funzionare con la pipe. Ho provato ...| tar Tczf xy_..., ...| tar Tcz -f xy_... ...| tar -czf xy_... -T e molte altre permutazioni, ma sto ottenendo solo tar: You must specify one of the '-Acdtrux', '--delete' or '--test-label' options, tar: -f: Cannot stat: No such file or directoryse si utilizza -fseparatamente da altre opzioni e tar: option requires an argument -- 'T'. Potresti aggiungere un esempio di utilizzo?
kostja,

Esempio di @kostja aggiunto.
rsanchez,

Mille grazie, rsanchez. Non so perché la variante con -T -alla fine tardell'elenco delle opzioni non ha funzionato, ma il tuo esempio ha funzionato. Sfortunatamente, la mia domanda in realtà aveva due parti: la fonte dell'errore e un possibile miglioramento. Mentre accedevi a quest'ultimo, Archemar eccelleva nel primo e aveva quasi il secondo diritto. Non sono sicuro di quale delle tue risposte accettare poiché entrambi sono stati ovviamente utili.
kostja,

1

Voglio integrare le altre due risposte con una soluzione zsh , che non analizza né ha bisogno di xargs . Tuttavia, non sono sicuro in questo momento, se soffre anche della limitazione della lunghezza della riga di comando.

  1. Definire una funzione che genera la chiave di ordinamento desiderata modificando $REPLY.

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

    Questo è equivalente al tuo sort -n -k1.4,1.9

  2. Genera un array $filescon i nomi di file ordinati con la funzione sopra:

    files=(*(o+sortkey))

    Questo equivale a ls | sort -n -k1.4,1.9

  3. Restituisci i primi 10.000 file con

    ${files[0,9999]}

    Questo equivale a ls | sort -n -k1.4,1.9 | head -n10000

Quindi, tutto sommato, questo dovrebbe fare il trucco:

sortkey() { REPLY=${REPLY[4,9]} }
files=(*(o+sortkey))
tar -czf xy_0_10000.tar.gz ${files[0,9999]}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.