example - linux find mv
¿Por qué no funciona find-exec mv{}./target/+? (4)
Quiero saber exactamente qué {} /;
y {} /+
y | xargs ...
| xargs ...
do. Por favor aclare esto con explicaciones.
Debajo de 3 comandos se ejecuta y sale el mismo resultado, pero el primer comando toma un poco de tiempo y el formato también es un poco diferente.
find . -type f -exec file {} /;
find . -type f -exec file {} /+
find . -type f | xargs file
Es porque 1st primero ejecuta el comando de file
para cada archivo que proviene del comando find
. Entonces, básicamente se ejecuta como:
file file1.txt
file file2.txt
Pero los últimos 2 encuentran que los comandos -exec
ejecutan el comando de archivo una vez para todos los archivos como a continuación:
file file1.txt file2.txt
Luego ejecuto los siguientes comandos en los que el primero se ejecuta sin problemas, pero el segundo da un mensaje de error.
find . -type f -iname ''*.cpp'' -exec mv {} ./test/ /;
find . -type f -iname ''*.cpp'' -exec mv {} ./test/ /+ #gives error:find: missing argument to `-exec''
Para el comando con {} /+
, me da el mensaje de error
find: missing argument to `-exec''
¿porqué es eso? ¿Puede alguien explicar por favor qué estoy haciendo mal?
El equivalente estándar de find -iname ... -exec mv -t dest {} +
para find
implementaciones que no admiten implementaciones -iname
o mv
que no admiten -t
es usar un shell para reordenar los argumentos :
find . -name ''*.[cC][pP][pP]'' -type f -exec sh -c ''
exec mv "$@" /dest/dir/'' sh {} +
Al usar -name ''*.[cC][pP][pP]''
, también evitamos la dependencia de la configuración regional actual para decidir cuál es la versión en mayúscula de c
o p
.
Tenga en cuenta que +
, contrario a ;
no es especial en ningún intérprete de comandos, por lo que no necesita ser cotizado (aunque las cotizaciones no dañarán, excepto, por supuesto, con shells como rc
que no son compatibles como operador de cotización).
El final /
in /dest/dir/
es para que mv
falle con un error en lugar de cambiar el nombre de foo.cpp
a /dest/dir
en el caso donde solo se encontró un archivo cpp
y /dest/dir
no existía o wasn '' t un directorio (o enlace simbólico al directorio).
Encontré el mismo problema en Mac OSX , usando un shell ZSH : en este caso no hay opción -t
para mv
, así que tuve que encontrar otra solución. Sin embargo, el siguiente comando tuvo éxito:
find .* * -maxdepth 0 -not -path ''.git'' -not -path ''.backup'' -exec mv ''{}'' .backup /;
El secreto fue citar las llaves . No es necesario que los refuerzos estén al final del comando exec
.
Probé bajo Ubuntu 14.04 (con shells BASH y ZSH ), funciona igual.
Sin embargo, al usar el signo +
, parece que debe estar al final del comando exec
.
La página del manual (o el manual en línea de GNU ) explica casi todo.
find -exec command {} /;
Para cada resultado, se ejecuta el command {}
. Todas las ocurrencias de {}
son reemplazadas por el nombre del archivo. ;
se antepone con una barra oblicua para evitar que el intérprete lo interprete.
find -exec command {} +
Cada resultado se agrega al command
y se ejecuta luego. Teniendo en cuenta las limitaciones de longitud de comando, creo que este comando se puede ejecutar más veces, con la página de manual que me respalda:
el número total de invocaciones del comando será mucho menor que el número de archivos coincidentes.
Tenga en cuenta esta cita de la página del manual:
La línea de comando está construida de la misma manera que xargs construye sus líneas de comando
Es por eso que no se permiten caracteres entre {}
y +
excepto en el espacio en blanco. +
hace que find detecte que los argumentos deben anexarse al comando al igual que xargs
.
La solución
Afortunadamente, la implementación de GNU de mv
puede aceptar el directorio de destino como un argumento, con -t
o el parámetro más largo --target
. Su uso será:
mv -t target file1 file2 ...
Su comando de find
convierte en:
find . -type f -iname ''*.cpp'' -exec mv -t ./test/ {} /+
Desde la página del manual:
-exec comando;
Ejecutar comando; verdadero si se devuelve 0 estado. Todos los siguientes argumentos para encontrar se toman como argumentos para el comando hasta que un argumento que consta de `; '' se encuentra. La cadena `{} ''se reemplaza por el nombre del archivo actual que se está procesando en todos los lugares en los argumentos del comando, no solo en los argumentos donde está solo, como en algunas versiones de find. Ambas construcciones pueden necesitar escaparse (con un `/ '') o cotizadas para protegerlas de la expansión del shell. Consulte la sección EJEMPLOS para ver ejemplos del uso de la opción -exec. El comando especificado se ejecuta una vez para cada archivo coincidente. El comando se ejecuta en el directorio de inicio. Hay problemas de seguridad inevitables que rodean el uso de la acción -exec; deberías usar la opción -execdir en su lugar.
-exec comando {} +
Esta variante de la acción -exec ejecuta el comando especificado en los archivos seleccionados, pero la línea de comando se construye agregando cada nombre de archivo seleccionado al final; el número total de invocaciones del comando será mucho menor que el número de archivos coincidentes. La línea de comando está construida de la misma manera que xargs construye sus líneas de comando. Solo se permite una instancia de `{} ''dentro del comando. El comando se ejecuta en el directorio de inicio.
no, la diferencia entre +
y /;
debe ser revertido +
Anexa los archivos al final del comando exec luego ejecuta el comando exec y /;
ejecuta el comando para cada archivo.
El problema es find . -type f -iname ''*.cpp'' -exec mv {} ./test/ /+
find . -type f -iname ''*.cpp'' -exec mv {} ./test/ /+
debe ser find . -type f -iname ''*.cpp'' -exec mv {} ./test/ +
find . -type f -iname ''*.cpp'' -exec mv {} ./test/ +
no hay necesidad de escapar o terminar el +
xargs que no he usado en mucho tiempo, pero creo que funciona como +.