¿Por qué no se comprimen todos los archivos y cómo mejorar la solución?

8

Tengo una carpeta con aproximadamente 20K archivos. Los archivos se nombran de acuerdo con el patrón xy_{\d1,5}_{\d4}\.abc, por ejemplo xy_12345_1234.abc. Quería comprimir los primeros 10K de ellos usando este comando:

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

sin embargo, el archivo resultante solo tenía unos 2K archivos dentro.

ls | sort -n -k1.4,1.9 | head -n10000 | wc -l sin embargo, devuelve 10000, como se esperaba.

Me parece que estoy malentendido algo básico aquí ...

Estoy usando zsh 5.0.2 en Linux Mint 17.1, GNU tar 1.27.1

EDITAR:

bifurcación como lo sugiere @Archemar suena muy plausible, con la última bifurcación sobrescribiendo el archivo resultante: el archivo contiene la 'cola' de los archivos: 7773 a 9999 .

resultado 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

Reemplazar -ccon -ro -uno funcionó en mi caso. El mensaje de error fuetar: Cannot update compressed archives

usando ambos -ry -ues inválido y falla contar: You may not specify more than one '-Acdtrux', '--delete' or '--test-label' option

sustituyendo -ccon -aparece ser válido también y no con el mismo tar: You must specify one of the '-Acdtrux', '--delete' or '--test-label' options, aunque yo no reconozco el tema azfy Acdtruxparece disjunta a mí.

EDITAR 2:

-T parece una buena manera, también he encontrado un ejemplo aquí .

Sin embargo cuando lo intento

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

bueno, tal vez los nombres de los archivos no llegan al alquitrán? Pero parece que lo hacen porque cuando ejecuto

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

Entonces, ¿por qué tar no ve los nombres de los archivos?

kostja
fuente
y si prueba a en lugar de c, en el comando tar?
Olivier Dulac
55
Relevante: Nols
analice
1
El archivo de OP no tiene nombres complicados.
Archemar
@ 8bittree - así como un consejo general para scripts de shell robustos, sí. pero, ¿qué sugiere en su lugar para trabajar con listas de archivos con los únicos únicos habituales?
kostja
1
@kostja que usaría find, que tiene la -print0opción de usar un byte nulo como delimitador en lugar de una nueva línea. sortpuede manejar eso con la -zbandera. head, desafortunadamente no maneja los delimitadores de bytes nulos, pero esta respuesta tiene una solución que se usa trpara intercambiar \ny \0antes y después head. tartiene --null -T -que leer nombres de archivo delimitados por nulos stdin.
8bittree

Respuestas:

12

has alcanzado el límite de xargs?

xargs --show-limit

tratar :

  • crear un .tgzarchivo ficticiotar czf xy_0_10000.tar.gz /hello/world
  • reemplazar -czfpor -Azf

cuando xarg llegue a su límite, bifurcará el comando, por lo que el comando que finalmente ejecutó fue

  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

Como cada alquitrán anula el anterior, solo debería obtener la última tar cejecución.

Editar:

1) de acuerdo con man taren unbuntu, -ay -r parece equivalente, anexar lo realiza (cualquiera) -A, --catenate, --concatenate

2) zip(no gzip) se puede usar para agregar un archivo, tal vez una opción gzip sea suficiente. (uso | xargs zip -qr xy_0_0000.zip, esto dará como resultado un archivo zip, no un .tar.gz)

3) para usar la solución de @ rsanchez
Es importante agregar la opción al alquitrán de manera adecuada, intente

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

where: -T -opción de uso medio -Ty uso -como argumento para -T(podría haber generado una lista de archivos /tmp/foo.lsty luego usar -T /tmp/foo.lst)

Archemar
fuente
¿podría a (= agregar) en lugar de c (= crear / sobrescribir) evitar esa limitación?
Olivier Dulac
@OlivierDulac ( Advertencia: esta es una suposición pura ) Probablemente no se resolverá ya que tar no puede crear archivos vacíos. Usted puede comprimir una carpeta vacía primero y utilizar a (add)para agregar los archivos en el archivo tar. Luego, puede abrir el tar y eliminar la carpeta (usando 7zip o algo así)
Ismael Miguel
@ismaelmiguel: Estoy bastante seguro de que felizmente creará el archivo. si no, solo:touch xy_0_10000.tar.gz && { _the full command here_ ; }
Olivier Dulac
1
@OlivierDulac Ese será un .gzarchivo no válido .
Ismael Miguel
Todas las páginas de manual que veo de manpages.ubuntu.com/manpages/vivid/en/man1/tar.1.html (15.04) de regreso a precisas (12.04) han -ragregado pero -aautocomprimido, lo cual no es equivalente. Y -rzno funciona: zippuede agregarse a un archivo existente porque el directorio no está comprimido, pero tarcon compresión comprime los metatdatos junto con los datos. Puede tar -rtrocear en un archivo sin comprimir y luego comprimir el resultado. O ...
dave_thompson_085
12

No hay necesidad de eso xargs. Si le da tarla -T -opción directamente , leerá los nombres de archivo de la entrada estándar.

Por ejemplo:

... | tar -T - -czf xy_0_10000.tar.gz
rsanchez
fuente
Parece que estoy usando la opción incorrectamente, no puedo hacer que funcione con la tubería. He intentado ...| tar Tczf xy_..., ...| tar Tcz -f xy_... ...| tar -czf xy_... -T y varias otras permutaciones, pero solo estoy obteniendo tar: You must specify one of the '-Acdtrux', '--delete' or '--test-label' options, tar: -f: Cannot stat: No such file or directorysi se usa por -fseparado de otras opciones y tar: option requires an argument -- 'T'. ¿Podría agregar un ejemplo de uso?
kostja
@kostja ejemplo agregado.
rsanchez
Muchas gracias, rsanchez. No estoy seguro de por qué la variante con -T -al final de la tarlista de opciones no funcionó, pero su ejemplo sí. Desafortunadamente, mi pregunta en realidad tenía dos partes: la fuente del error y una posible mejora. Mientras superaste a este último, Archemar se destacó en el primero y casi tenía el último derecho. No estoy seguro de cuál de sus respuestas aceptar ya que obviamente ambas fueron útiles.
kostja
1

Quiero complementar las otras dos respuestas con una solución zsh , que no analiza ls ni necesita xargs . Sin embargo, no estoy seguro en este momento, si también sufre la limitación de la longitud de la línea de comando.

  1. Defina una función que genere su clave de clasificación deseada modificando $REPLY.

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

    Esto es equivalente a tu sort -n -k1.4,1.9

  2. Genere una matriz $filescon los nombres de archivo ordenados con la función anterior:

    files=(*(o+sortkey))

    Esto es equivalente a ls | sort -n -k1.4,1.9

  3. Devuelva los primeros 10 000 archivos con

    ${files[0,9999]}

    Esto es equivalente a ls | sort -n -k1.4,1.9 | head -n10000

Entonces, en general, esto debería hacer el truco:

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