Tubería a comando mv

Estoy tratando de mover archivos desde la Terminal, pero solo los de los resultados de una grepconsulta.

ls -l | grep -i s02 | mv

¿Cuál es la mejor manera de completar el comando anterior?

¿A dónde quieres mover los archivos?

Respuestas (2)

Puede lograr esto simplemente ejecutando

cd directory/containing/the/files
mv *[sS]02* /path/to/target/

Para operaciones más complejas, también existe la opción de usar findpara encontrar todos los archivos relevantes. El ejemplo de su pregunta también podría escribirse como

cd directory/containing/the/files
find . -type f -maxdepth 1 -iname '*s02*' -exec mv {} /path/to/target/directory/ \;

Vale la pena echarle un vistazo man findpara ver qué otras opciones están disponibles.

Hace mucho tiempo, alguien me dijo que las expresiones regulares coinciden con cadenas y los globos coinciden/generan nombres de archivo. Posiblemente, man 3 glob pueda ayudar.

Por ejemplo con bash. Teniendo en cuenta los archivos a continuación

$ ls -1
test1
test2
test3

1) Para evitar sorpresas, echemos un vistazo primero a los comandos.

$ for i in test*; do echo mv $i $i.ext; done
mv test1 test1.ext
mv test2 test2.ext
mv test3 test3.ext

y ejecutar los comandos si esto es lo que queremos

$ for i in test*; do mv $i $i.ext; done
$ ls -1
test1.ext
test2.ext
test3.ext

Adapta el camino a tus necesidades.

2) Es posible usar sed y xargs . Probemos primero

$ ls -1 test* | sed 'p;s/test/test_/' | xargs -n2 printf "%s %s\n"
test2 test_2
test1 test_1
test3 test_3

y ejecutar los comandos si esto es lo que queremos

$ ls -1 test* | sed 'p;s/test/test_/' | xargs -n2 mv
$ ls -1
test_1
test_2
test_3

Espacios en el nombre del archivo

Estos scripts no funcionarán como se esperaba si los nombres de archivo incluyen espacios. En Unix, el espacio se usa como separador. Por ejemplo con los archivos

$ ls -1
test 1
test 2
test 3

está claro que los comandos a continuación no pueden funcionar como se esperaba

$ for i in test*; do echo mv $i $i.ext; done
mv test 1 test 1.ext
mv test 2 test 2.ext
mv test 3 test 3.ext

La solución es excluir el espacio de la lista de separadores.

$ IFS="`printf '\n\t'`"

y agréguelo a los comandos que deben procesar los nombres de archivo con espacios. El comando de abajo

$ IFS="`printf '\n\t'`"; for i in test*; do mv $i $i.ext; done

funciona como se esperaba

$ ls -1
test 1.ext
test 2.ext
test 3.ext

La siguiente opción es la cita de los argumentos.

for i in test*; do mv "$i" "$i.ext"; done

De esta forma es posible utilizar la rica variedad de filtros de Unix y evitar la limitación a la construcción "find... -exec... {}". Para otras limitaciones, consulte las notas debajo de la línea.

Notas sobre macOS

1) Citando de opengroup.org - Estándar de producto: Comandos y utilidades V4

1.4.21 sh
Pregunta 31: ¿Se ignora la variable de entorno IFS cuando se invoca el shell?
Respuesta: Sí
Justificación: La especificación permite que el comando sh ignore la configuración de la variable de entorno IFS en la invocación. La configuración de esta variable se ha utilizado para violar la seguridad en los sistemas que utilizan el shell para interpretar una llamada a las interfaces system() y execvp().
Referencia: Norma Técnica, Shell y Utilidades, Edición 6, Capítulo 4, Utilidades, sh, VARIABLES AMBIENTALES, IFS.

2) Citando de developer.apple.com - Entrada y salida de Shell

Puede modificar el comportamiento del comando de lectura modificando la variable de shell IFS (abreviatura de separadores de campo internos). El comportamiento predeterminado es dividir las entradas dondequiera que haya un espacio, una pestaña o una nueva línea. Cambiando esta variable,...

3) Citando de developer.apple.com - Declaraciones de control básico - Estándar para bucles

En el siguiente ejemplo, la lista es *.JPG...

#!/bin/sh
for i in *.JPG ; do
    mv "$i" "$(echo $i | sed 's/\.JPG$/.x/')"
    mv "$(echo $i | sed 's/\.JPG$/.x/')" "$(echo $i | sed 's/\.JPG$/.jpg/')"
done


Es posible que estos scripts no funcionen como se esperaba si hay caracteres especiales en el nombre del archivo. Reemplace dichos caracteres primero. Consulte Cómo eliminar un carácter especial . Hay docenas de artículos sobre cómo cambiar el nombre de los archivos con espacios y otros caracteres que causan problemas, por ejemplo, nombres de archivos con espacios que se rompen para bucle, comando de búsqueda . Es una buena idea deshacerse de dichos caracteres y traducir los nombres de archivo al formato que prefiera (por ejemplo, renombrar archivo ) antes de procesarlos en *nix. Consulte Corrección de nombres de archivo Unix/Linux/POSIX .

Esto fallará con nombres de archivo como test 1y similares. Tampoco hará lo que espera que haga si el directorio actual contiene archivos con nombres que comienzan con test.
No es necesario cambiar el nombre, asegurándose de usar opciones/herramientas que aseguren \0cadenas terminadas y ocuparse de configurar/usar variables es todo lo que se necesita. Consulte mywiki.wooledge.org/BashPitfalls y mywiki.wooledge.org/BashFAQ :-)
Bueno, en mi humilde opinión, es más seguro, eficiente y flexible deshacerse de los nombres de archivo patológicos y no preocuparse por las trampas, es decir, normalizar los nombres de archivo lo antes posible y procesarlos más tarde. Seguridad y modularidad es todo lo que se necesita.
Gracias por los enlaces, pero tal vez la gente debería centrarse en aprender cómo funciona un sistema y no cómo funciona mal. Si los scripts o programas de shell fallan en los nombres de archivo que contienen caracteres que el sistema de archivos (y el estándar) permiten, esos scripts/programas simplemente están dañados y deben corregirse.
No tengo ni idea de en qué debería centrarse la gente. Siéntase libre de probar renombrar archivos e informar problemas .
@VladimirBotka Trabajo principalmente en macOS, por lo que los espacios en los nombres de archivo son algo normal y común. Yo diría que serán comunes en cualquier lugar donde los archivos se creen/utilicen principalmente a través de una GUI en lugar de una línea de comandos.
A lo largo de los años, descubrí que las personas hacen lo que está permitido, no lo que tiene sentido cuando se trata de computadoras. Dado que Unix permite un espacio en un archivo, es mejor codificar para el espacio. Wikipedia incluye macOS en su lista de derivados de Unix. Apples decía que macOS se basa en Unix sólido como una roca.
@Gordon Davisson: la pregunta está etiquetada como "Unix", por lo tanto, la respuesta no es específica de "macOS". He agregado la sección sobre cómo procesar nombres de archivo con espacios. Tiene razón en que tales nombres de archivo son comunes, pero esta no es una razón para poner espacios en los nombres de archivo cuando no es necesario. Los espacios en los nombres de archivo son la otra parte del mundo creada por MS. Nadie en el mundo *nix lo usaría voluntariamente, lo que está claro en Probablemente demasiado tarde para una prohibición total de espacios en los nombres de archivo .
@Vladimir Botka ¿Dónde está la documentación?
@historystamp: No estamos en contradicción. Sí, la gente puede hacer lo que está permitido. No puedo evitar si alguien quiere dispararle en la pierna. Sí, es mejor codificar para el espacio. Aún así, mi preferencia es evitar espacios principalmente por seguridad. Sí, macOS es un derivado de UNIX. Hay muchas diferencias entre los derivados de Unix. No dude en etiquetarlo correctamente. (Me pregunto cuál podría ser la razón para defender tonterías tan obvias como los espacios en los nombres de archivo. ¿Cuál es la ventaja de tener un espacio en el nombre de archivo en lugar de, por ejemplo, un guión bajo?)
@VladimirBotka Los espacios en los nombres de los archivos coinciden con el lenguaje natural y son anteriores a Unix, por lo que no es una cosa de MS. Básicamente, si sus herramientas hacen que los espacios sean inseguros, entonces tiene herramientas deficientes. Utilice un ;decente; lenguaje de secuencias de comandos, por ejemplo, AppleScript VB, esquema tcl de python perl, etc. no uno porr como sh, etc.
@Mark: Buen punto que mencionaste sh . Es el shell común entre los sistemas y Ansible decidió convertirlo en el shell predeterminado para la gestión de sistemas multiplataforma con más de 1000 módulos , incluidos los módulos iosxr_*. Un sistema que muy probablemente fue una de las razones por las que IBM compró RH por 34.000 millones de dólares. No se equivoque, quiere usar las mismas herramientas pobres que yo.
Lamento decirlo, la solución para los problemas de espacios no es cambiar el valor de IFS. La solución es no usar un forbucle sobre el resultado de find. Usar find ... -exec(combinado con xargsy/o sh -c) es la forma canónica de Unix de hacer este tipo de cosas.
No existe tal cosa como "la forma canónica de Unix". Tal vez sea para macOS. El paradigma de Unix es "¡Herramientas, no políticas!" Por cierto. esta es la diferencia de la que estamos hablando desde el principio.