Estoy tratando de actualizar la marca de tiempo a la hora actual en todos los archivos xml en mi directorio (recursivamente). Estoy usando Mac OSX 10.8.5.
En aproximadamente 300,000 archivos, el siguiente echo
comando tarda 10 segundos :
for file in `find . -name "*.xml"`; do echo >> $file; done
Sin embargo, el siguiente touch
comando tarda 10 minutos . :
for file in `find . -name "*.xml"`; do touch $file; done
¿Por qué el eco es mucho más rápido que tocar aquí?
echo >> $file
agregará una nueva línea$file
y, por lo tanto, la modificará. Supongo que será lo mismo para OS / X. Si no quieres eso, úsaloecho -n >> $file
.touch `find . -name "*.xml"`
incluso más rápido que los dos anteriores?>>$file
touch
por qué invocar tantas veces?find . -name '*.xml' -print0 | xargs -0 touch
invocatouch
muchas menos veces (posiblemente solo una vez). Funciona en Linux, debería funcionar en OS X.Respuestas:
En bash,
touch
es un binario externo, peroecho
es un shell incorporado :Dado que
touch
es un binario externo, e invocatouch
una vez por archivo, el shell debe crear 300,000 instancias detouch
, lo que lleva mucho tiempo.echo
, sin embargo, es un shell integrado, y la ejecución de shell incorporado no requiere bifurcación en absoluto. En cambio, el shell actual realiza todas las operaciones y no se crean procesos externos; Esta es la razón por la cual es mucho más rápido.Aquí hay dos perfiles de las operaciones del shell. Puede ver que se dedica mucho tiempo a clonar nuevos procesos cuando se usa
touch
. El uso en/bin/echo
lugar de la cubierta incorporada debería mostrar un resultado mucho más comparable.Usando el tacto
Usando echo
fuente
Como otros han contestado, utilizando
echo
será más rápido quetouch
comoecho
es un comando que es comúnmente (aunque no necesariamente) integrado en la carcasa. Su uso prescinde de la sobrecarga del núcleo asociada con la ejecución de un nuevo proceso para cada archivo que obtienetouch
.Sin embargo, tenga en cuenta que la forma más rápida de lograr este efecto todavía es usarla
touch
, pero en lugar de ejecutar el programa una vez para cada archivo, es posible usar la-exec
opciónfind
para asegurarse de que solo se ejecute unas pocas veces. Este enfoque generalmente será más rápido ya que evita la sobrecarga asociada con un ciclo de shell:El uso de
+
(en lugar de\;
) confind ... -exec
ejecuta el comando solo una vez si es posible con cada archivo como argumento. Si la lista de argumentos es muy larga (como es el caso con 300,000 archivos), se realizarán varias ejecuciones con una lista de argumentos que tiene una longitud cercana al límite (ARG_MAX
en la mayoría de los sistemas).Otra ventaja de este enfoque es que se comporta de manera robusta con los nombres de archivo que contienen todos los caracteres de espacio en blanco, que no es el caso con el bucle original.
fuente
+1
para señalar el+
argumento de búsqueda . Creo que muchas personas no son conscientes de esto (yo no).find
tienen el+
argumento. Puede obtener un efecto similar canalizando axargs
.+
POSIX requiere la pieza, por lo que debe ser portátil.-print0
no lo esfind
tiene la opción disponible, pero solo la trata como si estuviera;
debajo de la superficie.echo
Es una concha incorporada. Por otro lado,touch
es un binario externo.Los componentes integrados de Shell son mucho más rápidos ya que no hay gastos generales involucrados en la carga del programa, es decir, no hay
fork
/exec
involucrado. Como tal, observaría una diferencia de tiempo significativa al ejecutar un comando incorporado frente a un comando externo una gran cantidad de veces.Esta es la razón por la cual las utilidades como
time
están disponibles como shell incorporadas.Puede obtener la lista completa de componentes integrados de shell diciendo:
Como se mencionó anteriormente, el uso de la utilidad en lugar de los resultados integrados genera una degradación significativa del rendimiento. A continuación se muestran las estadísticas del tiempo necesario para crear ~ 9000 archivos utilizando el builtin
echo
y la utilidadecho
:fuente
echo
binario en la mayoría de los sistemas (para mí es/bin/echo
), por lo que puede volver a intentar las pruebas de tiempo usando eso en lugar del incorporado