Tengo unos 15,000 archivos con nombres file_1.pdb, file_2.pdbetc. Puedo ordenar unos pocos miles de estos en orden haciendo:
cat file_{1..2000}.pdb >> file_all.pdb
Sin embargo, si hago esto para 15,000 archivos, me sale el error
-bash: /bin/cat: Argument list too long
He visto resolver este problema haciendo find . -name xx -exec xxesto, pero esto no preservaría el orden con el que se unen los archivos. ¿Cómo puedo conseguir esto?
files
find
cat
brace-expansion
nitrato de sodio
fuente
fuente

cat file_{1..15000}.pdbconstrucción funciona bien para mí.getconf ARG_MAXdebería decir.Respuestas:
Utilizando
find,sortyxargs:El
findcomando encuentra todos los archivos relevantes, luego imprime sus nombres de ruta parasorthacer un "ordenamiento de versiones" para obtenerlos en el orden correcto (si los números en los nombres de archivo hubieran sido rellenados con ceros a un ancho fijo, no hubiéramos necesitado-V).xargstoma esta lista de nombres de ruta ordenados y los ejecutacaten lotes tan grandes como sea posible.Esto debería funcionar incluso si los nombres de archivo contienen caracteres extraños como líneas nuevas y espacios. Usamos
-print0withfindpara darsortnombres terminados en nulos para ordenar, y lossortmaneja usando-z.xargslee también nombres terminados en nulo con su-0bandera.Tenga en cuenta que estoy escribiendo el resultado en un archivo cuyo nombre no coincide con el patrón
file_*.pdb.La solución anterior utiliza algunos indicadores no estándar para algunas utilidades. Estos son compatibles con la implementación de GNU de estas utilidades y al menos con la implementación de OpenBSD y macOS.
Los indicadores no estándar utilizados son
-maxdepth 1, para hacer quefindsolo ingrese el directorio superior pero no subdirectorios. POSIXY, usefind . ! -name . -prune ...-print0, parafindgenerar nombres de ruta terminados en nulo (esto fue considerado por POSIX pero rechazado). Se podría usar-exec printf '%s\0' {} +en lugar.-z, para hacersorttomar registros terminados en nulos. No hay equivalencia POSIX.-V, parasortordenar, por ejemplo,200después3. No hay equivalencia POSIX, pero podría reemplazarse por una clasificación numérica en partes específicas del nombre de archivo si los nombres de archivo tienen un prefijo fijo.-0, para hacerxargsregistros leídos con terminación nula. No hay equivalencia POSIX. POSIXY, uno necesitaría citar los nombres de archivo en un formato reconocido porxargs.Si los nombres de ruta se comportan bien, y si la estructura del directorio es plana (sin subdirectorios), uno podría prescindir de estos indicadores, excepto
-Vconsort.fuente
printf ‘file_%d.pdb\0’ {1..15000} | xargs -0 cat, o incluso con el punto de Kevin,echo file_{1..15000}.pdb | xargs cat. Lafindsolución tiene una sobrecarga considerablemente mayor ya que tiene que buscar esos archivos en el sistema de archivos, pero es más útil cuando algunos de los archivos pueden no existir.xargsmás quecateso se redirige (cadacatinvocación utilizaráxargsla salida estándar). Si hubiéramos dicho,xargs -0 sh -c 'cat >all.pdb'entonces tendría sentido usarlo en>>lugar de>, si eso es lo que estás insinuando.sort -n -k1.6que funcionaría (para el original, losfile_nnnnombres de archivo osort -n -k1.5para los que no tienen el guión bajo).Con
zsh(de dónde{1..15000}proviene ese operador):O para todos los
file_<digits>.pdbarchivos en orden numérico:(donde
<x-y>es un operador global que coincide con los números decimales xay. Sinxniy, es cualquier número decimal. Equivalente aextendedglob's[0-9]##okshglob' s+([0-9])(uno o más dígitos)).Con
ksh93, usando sucatcomando incorporado (por lo que no se ve afectado por ese límite de laexecve()llamada del sistema ya que no hay ejecución ):Con
bash/zsh/ksh93(que ayudazsh's{x..y}y tienenprintfincorporado):En un sistema GNU o compatible, también puede usar
seq:Para las
xargssoluciones basadas, se debe tener especial cuidado con los nombres de archivos que contienen espacios en blanco, comillas simples o dobles o barras invertidas.Me gusta para
-It's a trickier filename - 12.pdb, use:fuente
seq -f | xarg cat >es la solución más elegante y eficaz. (EN MI HUMILDE OPINIÓN).'"./-It'\''s a trickier filename - %.17g.pdb"'¿ tal vez ?Un bucle for es posible, y muy simple.
La desventaja es que invocas
catmuchas veces. Pero si no puede recordar exactamente cómo hacer las cosasfindy la sobrecarga de la invocación no es tan mala en su situación, entonces vale la pena tenerlo en cuenta.fuente
echo $i;en el cuerpo del bucle como un "indicador de progreso"fuente
seq -f file_%.10g.pdb 15000. Tenga en cuenta queseqno es un comando estándar.seq -fes una excelente forma de hacerlo. Lo recordaré.Premisa
No debe incurrir en ese error solo para 15k archivos con ese formato de nombre específico [ 1 , 2 ] .
Si está ejecutando esa expansión desde otro directorio y tiene que agregar la ruta a cada archivo, el tamaño de su comando será mayor y, por supuesto, puede ocurrir.
La solución ejecuta el comando desde ese directorio.
La mejor solución Si en cambio adiviné mal y lo ejecutas desde el directorio en el que están los archivos ... En
mi humilde opinión, la mejor solución es la de Stéphane Chazelas :
con printf o seq; probado en archivos de 15k con solo su número dentro de la memoria caché previa, es incluso el más rápido (en la actualidad, excepto el OP del mismo directorio en el que se encuentran los archivos).
Algunas palabras mas
Debería poder pasar a sus líneas de comando de shell más tiempo.
Su línea de comando tiene 213914 caracteres y contiene 15003 palabras.
cat file_{1..15000}.pdb " > file_all.pdb" | wc... incluso agregar 8 bytes para cada palabra es 333 938 bytes (0.3M) muy por debajo del 2097142 (2.1M) reportado
ARG_MAXen un kernel 3.13.0 o el 2088232 ligeramente más pequeño reportado como "Longitud máxima de comando que podríamos realmente utilizar " porxargs --show-limitsEche un vistazo en su sistema a la salida de
Solución guiada de la pereza
En casos como este, prefiero trabajar con bloques, incluso porque generalmente sale una solución eficiente en el tiempo.
La lógica (si la hay) es que soy demasiado vago para escribir 1 ... 1000 1001..2000, etc., etc.
Así que le pido a un script que lo haga por mí.
Solo después de comprobar que la salida es correcta, la redirijo a un script.
... pero la pereza es un estado mental .
Como soy alérgico a
xargs(realmente debería haberlo usadoxargsaquí) y no quiero comprobar cómo usarlo, termino puntualmente para reinventar la rueda como en los ejemplos a continuación (tl; dr).Tenga en cuenta que, dado que los nombres de los archivos están controlados (sin espacios, líneas nuevas ...), puede seguir fácilmente algo como el script a continuación.
tl; dr
Versión 1: pase como parámetro opcional el primer número de archivo, el último, el tamaño del bloque, el archivo de salida
Versión 2
Llamando a bash para la expansión (un poco más lento en mis pruebas ~ 20%).
Por supuesto, puede avanzar y deshacerse por completo de
seq[ 3 ] (de coreutils) y trabajar directamente con las variables en bash, o usar python, o compilar un programa de CA para hacerlo [ 4 ] ...fuente
%ges la abreviatura de%.6g. Representaría 1,000,000 como 1e + 06 por ejemplo.xargs, zsh'szargsoksh93'scommand -x.seqno es un bash incorporado, es un comando de GNU coreutils.seq -f %g 1000000 1000000salidas 1e + 06 incluso en la última versión de coreutils.xarg... pero entiendo que es personal y tal vez solo está relacionado conmigo.Otra forma de hacerlo podría ser
fuente