¿Cómo puedo encontrar archivos y luego usar xargs para moverlos?

28

Quiero encontrar algunos archivos y luego moverlos.

Puedo encontrar el archivo con:

$ find /tmp/ -ctime -1 -name x*

Traté de moverlos a mi ~/playdirectorio con:

$ find /tmp/ -ctime -1 -name x* | xargs mv ~/play/

Pero eso no funcionó. Obviamente mv necesita dos argumentos.
¿No está seguro de si (o cómo) hacer referencia al 'elemento actual' de xargs en el comando mv?

Michael Durrant
fuente
3
¿Por qué? Puede usar marcador de posición con -I:, find . | xargs -I'{}' mv '{}' ~/play/pero como dice el hombre, eso "implica -xy -L 1". Así que no hay ganancia. Mejor que sea simple y usarfind . -exec mv '{}' ~/play/ \;
manatwork
Publique como respuesta para ver los votos si no le importa :)
Michael Durrant
Solo pregunté por su razón, ya que tenía la sensación de que no entendía el punto. Si Drav Sloan agrega la nota sobre las opciones implícitas, su respuesta será lo mejor que pueda escribir. Así que mejor ve con eso.
manatwork
posible duplicado del patrón Buscar y mover
slm
@manatwork He editado mi respuesta para reflejar esos puntos duder :)
Drav Sloan

Respuestas:

43

Mire la respuesta de Stephane para el mejor método, mire mi respuesta por razones para no usar las soluciones más obvias (y las razones por las cuales no son las más eficientes).

Puede usar la -Iopción de xargs:

find /tmp/ -ctime -1 -name "x*" | xargs -I '{}' mv '{}' ~/play/

Que funciona en un mecanismo similar a findy {}. También citaría su -nameargumento (porque un archivo que comienza xen el directorio actual se englobaría y pasaría como un argumento para encontrar, ¡lo que no dará el comportamiento esperado!).

Sin embargo, como lo señala manatwork, como se detalla en la xargspágina man:

   -I replace-str
          Replace occurrences of replace-str in the initial-arguments with
          names read from standard input.  Also, unquoted  blanks  do  not
          terminate  input  items;  instead  the  separator is the newline
          character.  Implies -x and -L 1.

Lo importante a tener en cuenta es que -L 1significa que solo se procesará una línea de salida finda la vez. Esto significa que es sintácticamente lo mismo que:

find /tmp/ -ctime -1 -name "x*" -exec mv '{}' ~/play/

(que ejecuta una sola mvoperación para cada archivo).

Incluso usando el -0argumento GNU xargs y el find -print0argumento causa exactamente el mismo comportamiento de -I- esto es para clone()un proceso para cada archivo mv:

find . -name "x*" -print0 | strace xargs -0 -I '{}' mv '{}' /tmp/other

.
.
read(0, "./foobar1/xorgslsala11\0./foobar1"..., 4096) = 870
mmap(NULL, 135168, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) =     0x7fbb82fad000
open("/usr/lib/x86_64-linux-gnu/gconv/gconv-modules.cache", O_RDONLY) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=26066, ...}) = 0
mmap(NULL, 26066, PROT_READ, MAP_SHARED, 3, 0) = 0x7fbb82fa6000
close(3)                                = 0
clone(child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD,         child_tidptr=0x7fbb835af9d0) = 661
wait4(-1, [{WIFEXITED(s) && WEXITSTATUS(s) == 0}], 0, NULL) = 661
--- SIGCHLD (Child exited) @ 0 (0) ---
clone(child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD,         child_tidptr=0x7fbb835af9d0) = 662
wait4(-1, [{WIFEXITED(s) && WEXITSTATUS(s) == 0}], 0, NULL) = 662
--- SIGCHLD (Child exited) @ 0 (0) ---
.
.
.
Drav Sloan
fuente
Eso supone que los nombres de archivo no contienen caracteres de nueva línea, comillas simples, comillas dobles o barras invertidas.
Stéphane Chazelas
17

Con herramientas GNU:

find /tmp/ -ctime -1 -name 'x*' -print0 |
  xargs -r0 mv -t ~/play/

La opción -t( --target) es específica de GNU. -print0, -r, -0, Mientras que no estándar y originarios de GNU también se encuentran en algunas otras implementaciones, como en algunos BSDs.

POSIXY:

find /tmp/ -ctime -1 -name 'x*' -exec sh -c '
  exec mv "$@" ~/play/' sh {} +

Ambos ejecutan tan pocos mvcomandos como sea necesario y funcionan con los caracteres que puedan contener los nombres de archivo. El GNU One puede tener la ventaja de seguir findbuscando archivos mientras mvcomienza a mover el primer lote.

Tenga en cuenta que todos los archivos y directorios terminarán en un directorio, tenga cuidado con los conflictos si varios archivos en diferentes directorios tienen el mismo nombre.

Stéphane Chazelas
fuente
Esta solución tiene un rendimiento mucho mejor, ya que requiere mvuna vez todos los argumentos (o todos -Lo -n, si se proporcionan). De lo contrario, llamar mva cada archivo se volverá viejo (y lento) rápidamente.
r2evans
1

Quizás este comando es posible ahora y no fue en 2013, pero esto funciona perfectamente para mí:

ls pattern* | xargs mv -t DESTINATION/

La -tclave coloca primero la carpeta de destino, liberando el mvcomando para tener todos los últimos argumentos como solo los archivos que se moverán.

Nikhil VJ
fuente
1
esta fue la solución más simple que funcionó para mí
ptetteh227
0

Puede probar con el siguiente comando y probado y funcionó bien

find /tmp/ -ctime -1 -type f -name "x*" -exec mv -t ~/play/ {} \;
Praveen Kumar BS
fuente