Tengo un directorio que contiene 10144911 archivos. Hasta ahora he intentado lo siguiente:
for f in ls; do sed -i -e 's/blah/blee/g' $f; done
Se estrelló mi caparazón, ls
está en una tilda pero no puedo entender cómo hacer uno.
ls | xargs -0 sed -i -e 's/blah/blee/g'
Demasiados argumentos para sed
find . -name "*.txt" -exec sed -i -e 's/blah/blee/g' {} \;
No podía bifurcar más, no más memoria
¿Alguna otra idea sobre cómo crear este comando amable? Los archivos no necesitan comunicarse entre sí. ls | wc -l
parece funcionar (muy lento), por lo que debe ser posible.
sed
cada archivo. No estoy seguro de si hay una manera de abrir, editar, guardar y cerrar una serie de archivossed
; Si la velocidad es esencial, es posible que desee utilizar un programa diferente, tal vez Perl o Python.sed
es probablemente más rápido que el iniciopython
operl
también, excepto si hace todo en ese intérprete.Respuestas:
Prueba esto:
Solo alimentará un nombre de archivo a cada invocación de
sed
. Eso resolverá el problema de "demasiados argumentos para sed". La-P
opción debe permitir que se bifurquen varios procesos al mismo tiempo. Si 0 no funciona (se supone que debe ejecutar tantos como sea posible), intente con otros números (10? 100? ¿El número de núcleos que tiene?) Para limitar el número.fuente
find . -name \*.txt -print0
para evitar que la cáscara de ampliar el pegote y tratando de alloc espacio para 10 millones de argumentos a encontrar .He probado este método (y todos los demás) en 10 millones de archivos (vacíos), llamados "hola 00000001" a "hola 10000000" (14 bytes por nombre).
ACTUALIZACIÓN: ahora he incluido una ejecución de cuatro núcleos en el
'find |xargs'
método (todavía sin 'sed'; solo echo> / dev / null) ..Aquí hay un resumen de cómo les fue a las respuestas proporcionadas cuando se ejecutaron contra los datos de prueba mencionados anteriormente. Estos resultados involucran solo los gastos generales básicos; es decir, 'sed' no fue llamado. Es casi seguro que el proceso sed requerirá más tiempo, pero pensé que sería interesante ver cómo se comparan los métodos simples.
El
'find |xargs'
método de Dennis , usando un solo núcleo, tomó * 4 horas y 21 minutos ** más tiempo que elbash array
método en unano sed
ejecución ... Sin embargo, la ventaja multinúcleo que ofrece 'find' debería superar las diferencias de tiempo que se muestran cuando se solicita sed procesando los archivos ...fuente
Otra oportunidad para el hallazgo completamente seguro :
fuente
Esto es principalmente fuera de tema, pero podría usar
El principal beneficio aquí (más
... xargs ... -I {} ... sed ...
) es la velocidad: evitas invocarsed
10 millones de veces. Sería aún más rápido si pudieras evitar usar Python (ya que Python es un poco lento, relativamente), por lo que Perl podría ser una mejor opción para esta tarea. No estoy seguro de cómo hacer el equivalente convenientemente con Perl.La forma en que esto funciona es que
xargs
invocará a Python con tantos argumentos como pueda caber en una sola línea de comando, y seguirá haciéndolo hasta que se quede sin argumentos (que están siendo suministrados porls -f *.txt
). El número de argumentos para cada invocación dependerá de la longitud de los nombres de archivo y, um, algunas otras cosas. Lafileinput.input
función produce líneas sucesivas de los archivos nombrados en los argumentos de cada invocación, y lainplace
opción le dice que "atrape" mágicamente la salida y la use para reemplazar cada línea.Tenga en cuenta que el
replace
método de cadena de Python no usa expresiones regulares; si los necesita, debeimport re
usarlosprint re.sub(line, "blah", "blee")
. Son RegExps compatibles con Perl, que son una especie de versiones fuertemente fortificadas de las que obtienessed -r
.editar
Como akira menciona en los comentarios, la versión original que usa un glob (
ls -f *.txt
) en lugar delfind
comando no funcionaría porque los globos son procesados por el propio shell (bash
). Esto significa que incluso antes de ejecutar el comando, se sustituirán 10 millones de nombres de archivo en la línea de comando. Esto está prácticamente garantizado para superar el tamaño máximo de la lista de argumentos de un comando. Puede utilizarxargs --show-limits
para obtener información específica del sistema sobre esto.También se tiene en cuenta el tamaño máximo de la lista de argumentos
xargs
, lo que limita el número de argumentos que pasa a cada invocación de python de acuerdo con ese límite. Dadoxargs
que todavía tendrá que invocar Python varias veces, la sugerencia de Akira para usaros.path.walk
para obtener la lista de archivos probablemente le ahorrará algo de tiempo.fuente
os.path.walk()
?.
y..
. Ciertamente, hay otras formas de hacerlo (es decirfind
), pero estoy tratando de mantenerme lo más cerca posible de lo que entiende el OP. Esta es también la razón para no usaros.path.walk
.os.path.walk
bastante facilidad.Tratar:
fuente
ls -f
seria mejor; ¿realmente quieres esperarstat()
y ordenar tantos archivos?