¿Podría alguien proporcionar el código para hacer lo siguiente? Suponga que hay un directorio de archivos, todos los cuales deben ejecutarse a través de un programa. El programa emite los resultados a la salida estándar. Necesito un script que vaya a un directorio, ejecute el comando en cada archivo y concatene la salida en un archivo de salida grande.
Por ejemplo, para ejecutar el comando en 1 archivo:
$ cmd [option] [filename] > results.out
ls <directory> | xargs cmd [options] {filenames put in here automatically by xargs} [more arguments] > results.out
ls
para conducirxargs
. Sicmd
está escrito de manera competente, tal vez simplemente pueda hacerlocmd <wildcard>
.Respuestas:
El siguiente código bash pasará $ file al comando donde $ file representará cada archivo en / dir
Ejemplo
fuente
/dir/
, entonces el ciclo todavía se ejecuta una vez con un valor de '*' para$file
, lo que puede ser indeseable. Para evitar esto, habilite nullglob mientras dure el ciclo. Agregue esta línea antes del cicloshopt -s nullglob
y esta línea después del cicloshopt -u nullglob #revert nullglob back to it's normal default state
.done >results.out
(y probablemente luego pueda sobrescribir en lugar de agregar, como he supuesto aquí).Qué tal esto:
-maxdepth 1
El argumento evita que find descienda recursivamente en cualquier subdirectorio. (Si desea que se procesen dichos directorios anidados, puede omitir esto).-type -f
especifica que solo se procesarán archivos sin formato.-exec cmd option {}
le dice que se ejecutecmd
con el especificadooption
para cada archivo encontrado, con el nombre de archivo sustituido por{}
\;
denota el final del comando.cmd
ejecuciones individuales se redirige aresults.out
Sin embargo, si le importa el orden en que se procesan los archivos, es mejor que escriba un bucle. Creo que
find
procesa los archivos en orden de inodo (aunque podría estar equivocado al respecto), lo que puede no ser lo que desea.fuente
stat
ysort
, que por supuesto depende de los criterios de clasificación.-exec
opción? ¿Tengo que envolverlos entre comillas simples o algo así?find
es siempre la mejor opción porque puede filtrar por patrón de nombre de archivo con la opción-name
y puede hacerlo en un solo comando.-exec
opciones:find . -name "*.txt" -exec echo {} \; -exec grep banana {} \;
Estoy haciendo esto en mi frambuesa pi desde la línea de comandos ejecutando:
fuente
Las respuestas aceptadas / altamente votadas son geniales, pero carecen de algunos detalles esenciales. Esta publicación cubre los casos sobre cómo manejar mejor cuando falla la expansión del nombre de ruta del shell (glob), cuando los nombres de archivo contienen líneas nuevas incrustadas / símbolos de guión y mueven la redirección de salida del comando fuera del ciclo for al escribir los resultados en un expediente.
Cuando se ejecuta la expansión de glob shell,
*
existe la posibilidad de que la expansión falle si no hay archivos presentes en el directorio y se pasará una cadena glob no expandida al comando que se ejecutará, lo que podría tener resultados no deseados. Elbash
shell proporciona una opción de shell extendida para este usonullglob
. Entonces, el bucle se convierte básicamente de la siguiente manera dentro del directorio que contiene sus archivosEsto le permite salir de forma segura del ciclo for cuando la expresión
./*
no devuelve ningún archivo (si el directorio está vacío)o de una manera compatible con POSIX (
nullglob
esbash
específico)Esto le permite ir dentro del ciclo cuando la expresión falla por una vez y la condición
[ -f "$file" ]
verifica si la cadena no expandida./*
es un nombre de archivo válido en ese directorio, lo que no sería. Entonces, en caso de falla de esta condición, el usocontinue
vuelve alfor
bucle que no se ejecutará posteriormente.También tenga en cuenta el uso de
--
justo antes de pasar el argumento del nombre de archivo. Esto es necesario porque, como se señaló anteriormente, los nombres de archivo de shell pueden contener guiones en cualquier parte del nombre de archivo. Algunos de los comandos de shell interpretan eso y los tratan como una opción de comando cuando el nombre no es cita correctamente y ejecuta el comando pensando si se proporciona el indicador.Las
--
señales de la gama de opciones de línea de comandos en ese caso, que significa que el comando no deben analizar todas las cadenas más allá de este punto como opciones de órdenes, pero sólo como nombres de archivo.La doble cita de los nombres de archivo resuelve correctamente los casos en que los nombres contienen caracteres globales o espacios en blanco. Pero los nombres de archivo * nix también pueden contener nuevas líneas en ellos. Por lo tanto, limitamos los nombres de archivo con el único carácter que no puede ser parte de un nombre de archivo válido: el byte nulo (
\0
). Dado quebash
internamente utilizaC
cadenas de estilo en las que se utilizan los bytes nulos para indicar el final de la cadena, es el candidato adecuado para esto.Entonces, usando la
printf
opción de shell para delimitar archivos con este byte NULL usando la-d
opción deread
comando, podemos hacer a continuaciónLos
nullglob
yprintf
se envuelven, lo(..)
que significa que básicamente se ejecutan en un subconjunto (shell secundario), porque para evitar lanullglob
opción de reflejarse en el shell principal, una vez que el comando sale. La-d ''
opción deread
comando no es compatible con POSIX, por lo que necesita unbash
shell para que esto se haga. Usando elfind
comando esto se puede hacer comoPara
find
implementaciones que no son compatibles-print0
(aparte de las implementaciones de GNU y FreeBSD), esto se puede emular usandoprintf
Otra solución importante es mover la redirección fuera del ciclo for para reducir una gran cantidad de E / S de archivo. Cuando se usa dentro del bucle, el shell debe ejecutar llamadas al sistema dos veces para cada iteración del bucle for, una para abrir y otra para cerrar el descriptor de archivo asociado con el archivo. Esto se convertirá en un cuello de botella en su rendimiento para ejecutar iteraciones grandes. La sugerencia recomendada sería moverlo fuera del ciclo.
Extendiendo el código anterior con estas correcciones, podría hacer
que básicamente pondrá el contenido de su comando para cada iteración de su entrada de archivo en stdout y cuando finalice el bucle, abra el archivo de destino una vez para escribir el contenido de stdout y guardarlo. La
find
versión equivalente de la misma seríafuente
Una forma rápida y sucia que hace el trabajo a veces es:
Por ejemplo, para encontrar el número de líneas en todos los archivos en el directorio actual, puede hacer:
fuente
~/.local/share/steam
. Ran steam. Eliminó todo en el sistema propiedad del usuario". informe de error.Necesitaba copiar todos los archivos .md de un directorio a otro, así que esto es lo que hice.
for i in **/*.md;do mkdir -p ../docs/"$i" && rm -r ../docs/"$i" && cp "$i" "../docs/$i" && echo "$i -> ../docs/$i"; done
Lo cual es bastante difícil de leer, así que vamos a analizarlo.
primer CD en el directorio con sus archivos,
for i in **/*.md;
para cada archivo en su patrónmkdir -p ../docs/"$i"
cree ese directorio en una carpeta de documentos fuera de la carpeta que contiene sus archivos. Lo que crea una carpeta adicional con el mismo nombre que ese archivo.rm -r ../docs/"$i"
eliminar la carpeta adicional que se crea como resultado demkdir -p
cp "$i" "../docs/$i"
Copie el archivo realecho "$i -> ../docs/$i"
Echo lo que hiciste; done
Vivir feliz para siemprefuente
**
que funcione, seglobstar
debe configurar la opción de shell:shopt -s globstar
Puedes usar
xarg
ls | xargs -L 1 -d '\n' your-desired-command
-L 1
hace pasar 1 artículo a la vez-d '\n'
La salida dels
make se divide según la nueva línea.fuente
Basado en el enfoque de @Jim Lewis:
Aquí hay una solución rápida usando
find
y también ordenando archivos por su fecha de modificación:Para ordenar ver:
http://www.commandlinefu.com/commands/view/5720/find-files-and-list-them-sorted-by-modification-time
fuente
-print0
defind
y-0
para losxargs
que utilizan el carácter nulo en lugar de cualquier espacio en blanco (incluyendo saltos de línea).-print0
es algo que ayuda, pero toda la tubería necesita usar algo como esto, ysort
no lo esCreo que la solución simple es:
fuente
Máxima profundidad
Descubrí que funciona bien con la respuesta de Jim Lewis, solo agregue un poco como esto:
Orden de clasificación
Si desea ejecutar en orden de clasificación, modifíquelo así:
Solo por un ejemplo, esto se ejecutará con el siguiente orden:
Profundidad ilimitada
Si desea ejecutar en profundidad ilimitada por ciertas condiciones, puede usar esto:
luego coloque encima de cada archivo en los directorios secundarios de esta manera:
y en algún lugar del cuerpo del archivo principal:
fuente