bash - sustituir - reemplazar un texto en linux
Modificar la cadena de reemplazo en xargs (8)
los archivos deben ser renombrados / movidos de
<name>.txt
a/foo/<name>.bar.txt
Puede usar la utilidad de rename
, por ejemplo:
rename s//.txt$//.txt/.bar/g *.txt
Sugerencia: la sintaxis de sustitución es similar a sed
o vim
.
A continuación, mueva los archivos a un directorio de destino utilizando mv
:
mkdir /some/path
mv *.bar /some/path
Para renombrar archivos en subdirectorios basados en alguna parte de su nombre, verifique que:
-p
/--mkpath
/--make-dirs
Crea cualquier directorio inexistente en la ruta de destino.
Pruebas:
$ touch {1..5}.txt
$ rename --dry-run "s/.txt$/.txt.bar/g" *.txt
''1.txt'' would be renamed to ''1.txt.bar''
''2.txt'' would be renamed to ''2.txt.bar''
''3.txt'' would be renamed to ''3.txt.bar''
''4.txt'' would be renamed to ''4.txt.bar''
''5.txt'' would be renamed to ''5.txt.bar''
Cuando estoy usando xargs
veces no necesito usar explícitamente la cadena de reemplazo:
find . -name "*.txt" | xargs rm -rf
En otros casos, quiero especificar la cadena de reemplazo para hacer cosas como:
find . -name "*.txt" | xargs -I ''{}'' mv ''{}'' /foo/''{}''.bar
El comando anterior movería todos los archivos de texto bajo el directorio actual a /foo
y agregará la bar
extensión a todos los archivos.
Si en lugar de anexar algún texto a la cadena de reemplazo, quisiera modificar esa cadena de modo que pudiera insertar algún texto entre el nombre y la extensión de los archivos, ¿cómo podría hacerlo? Por ejemplo, digamos que quiero hacer lo mismo que en el ejemplo anterior, pero los archivos deben ser renombrados / movidos de <name>.txt
a /foo/<name>.bar.txt
(en lugar de /foo/<name>.txt.bar
).
ACTUALIZACIÓN : logro encontrar una solución:
find . -name "*.txt" | xargs -I{} /
sh -c ''base=$(basename $1) ; name=${base%.*} ; ext=${base##*.} ; /
mv "$1" "foo/${name}.bar.${ext}"'' -- {}
Pero me pregunto si hay una solución más corta / mejor.
Añadiendo que el artículo de la wikipedia es sorprendentemente informativo
Truco de la concha
Otra forma de lograr un efecto similar es utilizar un intérprete de comandos como el comando lanzado y tratar con la complejidad de ese shell, por ejemplo:
$ mkdir ~/backups
$ find /path -type f -name ''*~'' -print0 | xargs -0 bash -c ''for filename; do cp -a "$filename" ~/backups; done'' bash
El siguiente comando construye el comando move con xargs, reemplaza la segunda aparición de ''.'' con ''.bar.'', luego ejecuta los comandos con bash, trabajando en mac OSX.
ls *.txt | xargs -I {} echo mv {} foo/{} | sed ''s//./.bar./2'' | bash
En casos como este, un ciclo while sería más legible:
find . -name "*.txt" | while IFS= read -r pathname; do
base=$(basename "$pathname"); name=${base%.*}; ext=${base##*.}
mv "$pathname" "foo/${name}.bar.${ext}"
done
Tenga en cuenta que puede encontrar archivos con el mismo nombre en diferentes subdirectorios. ¿Estás de acuerdo con que los duplicados sean mv
por mv
?
Es posible hacer esto en una sola pasada (probada en GNU) evitando el uso de asignaciones variables temporales
find . -name "*.txt" | xargs -I{} sh -c ''mv "$1" "foo/$(basename ${1%.*}).new.${1##*.}"'' -- {}
Inspirado por una respuesta de @justaname anterior, este comando que incorpora Perl one-liner lo hará:
find ./ -name /*.txt | perl -p -e ''s/^(.*//(.*)/.txt)$/mv $1 .//foo//$2.bar.txt/'' | bash
Si puedes usar algo que no sea bash / sh, Y esto es solo por un "mv" de fantasía ... puedes probar el venerable script "rename.pl". Lo uso en Linux y cygwin en Windows todo el tiempo.
http://people.sc.fsu.edu/~jburkardt/pl_src/rename/rename.html
rename.pl ''s/^(.*?)/.(.*)$//1-new_stuff_here./2/'' list_of_files_or_glob
También puede usar un parámetro "-p" para renombrar.pl para que le diga lo que HABRÍA HECHO, sin hacerlo realmente.
Acabo de probar lo siguiente en mi c: / bin (entorno cygwin / windows). Usé el "-p" para escupir lo que habría hecho. Este ejemplo solo divide la base y la extensión, y agrega una cadena entre ellos.
perl c:/bin/rename.pl -p ''s/^(.*?)/.(.*)$//1-new_stuff_here./2/'' *.bat
rename "here.bat" => "here-new_stuff_here.bat"
rename "htmldecode.bat" => "htmldecode-new_stuff_here.bat"
rename "htmlencode.bat" => "htmlencode-new_stuff_here.bat"
rename "sdiff.bat" => "sdiff-new_stuff_here.bat"
rename "widvars.bat" => "widvars-new_stuff_here.bat"
Si tienes GNU Parallel http://www.gnu.org/software/parallel/ instalado, puedes hacer esto:
find . -name "*.txt" | parallel ''ext="{/}" ; mv -- {} foo/{/.}.bar.${ext##*.}''
Mira los videos introductorios de GNU Parallel para obtener más información: https://www.youtube.com/playlist?list=PL284C9FF2488BC6D1