Anteponer al nombre del archivo con el comando buscar

Anteponer al nombre del archivo con el comando buscar

Hay alguna maneracon solo el comando buscaranteponer una cadena a los nombres de archivos?

Para que esto:

201a.txt
201b.png
...

Se convierte en esto:

foo_201a.txt
foo_201b.png
...

Este:

find . -name '201*' -execdir mv {} foo_{} \;

No funciona porque la {}parte incluye el principio ./del nombre del archivo y, por lo tanto, intenta escribir en foo_./201*.

Si esto no es posible solo con buscar, ¿cuál es la forma más portátil (léase: solo coreutils, sin scripts de shell, más fácil de entender) de anteponer una cadena a los nombres de archivos?

Respuesta1

No. Pero el renamecomando ofrece una solución sencilla.

$ ls -1
201a.txt
201b.png
$ rename 201 foo_201 201*
$ ls -1
foo_201a.txt
foo_201b.png
$

Respuesta2

Qué tal si

find . -name '201*' -execdir basename {} \; | xargs -I{} mv {} foo_{}

basenamees proporcionado por coreutilsy desde que xargslo proporciona findutilsdebe ser al menos tan portátil como find -execdirél mismo.


Alternativamente, usar solo funciones de shell POSIX

find . -name '201*' -execdir sh -c 'mv "$1" "foo_${1#*/}"' sh {} \;

Respuesta3

Esto no es posible findsolo, ni siquiera con GNU find. GNU find puede imprimir archivos sin el prefijo de la línea de comando y colocando otro prefijo en su lugar, usando -printf foo_%pen lugar de -print, pero no hay nada similar para -exec.

(Puedes usar find -printf 'mv foo_%p …' | sh, si te gusta vivir peligrosamente. Esto solo funciona con nombres de archivos "dóciles" y se rompe terriblemente si hay espacios, comillas y otros caracteres especiales en los nombres de los archivos. Así que no hagas esto).

La forma estándar de hacer esto (de una manera que funciona en cualquier sistema POSIX, y también de una manera común) es llamar a un shell para realizar la manipulación de la cadena.

find . -name '201*' -exec sh -c 'mv -- "$0" "${0%/*}/foo_${0##*/}"' {} \;

No lo uso -execdirporque es una extensión GNU y pediste portabilidad. Tenga en cuenta que {}se pasa al shell como argumento. Nunca lo use {}dentro del código de shell: no solo porque no es portátil, sino más importantemente porque haría que el nombre del archivo se interprete como código de shell, lo que falla si el nombre del archivo contiene caracteres especiales.

En los sistemas POSIX modernos (cualquier cosa de la última década), puede acelerar un poco este comando agrupando las llamadas al shell.

find . -name '201*' -exec sh -c 'for x do mv -- "$x" "${x%/*}/foo_${x##*/}"; done' sh {} +

Alternativamente, en ksh, bash o zsh, puedes usar globbing recursivo en lugar de llamar a find.

set -o globstar # ksh only
shopt -s globstar # bash only
for x in **/201*; do
  mv -- "$x" "${x%/*}/foo_${x##*/}"
done

Respuesta4

Podrías usar un asterisco ( *) en su lugar, lo que elimina la ./parte:

find * -name '201*' -exec mv {} foo_{} \;  

información relacionada