2009-07-06 16 views
160

Hay varios archivos en un directorio que comienzan con fgh prefijo, por ejemplo:Cambiar el nombre de varios archivos en Unix

fghfilea 
fghfileb 
fghfilec 

Quiero cambiar el nombre de todos ellos, para empezar jkl prefijo. ¿Hay un solo comando para hacer eso en lugar de cambiar el nombre de cada archivo individualmente?

+1

cheque aquí: http: // theunixshell.blogspot.com/2013/01/bulk-renaming-of-files-in-unix.html – Vijay

+0

Pregunta relacionada: [Mejor manera de cambiar el nombre de los archivos en función de varios patrones] (http://stackoverflow.com/a/25597051/2654678). –

Respuesta

205

Existen varias formas, pero el uso de rename probablemente sea el más fácil.

Utilizando una versión de rename:

rename 's/^fgh/jkl/' fgh* 

Usando otra versión de rename (igual que Judy2K's answer):

rename fgh jkl fgh* 

usted debe comprobar página principal de la plataforma para ver cuál de los anteriores.

+4

+1 Ni siquiera sabía acerca de cambiar el nombre ... Ahora puedo dejar de usar un bucle for con mv y sed ... ¡Gracias! – balpha

+0

¿Estás seguro de que esto funcionará? ¿O confundiste un par de corrientes de tu mente en la misma línea? – nik

+0

Funciona en mi máquina (Ubuntu 8.10). – Stephan202

8
rename fgh jkl fgh* 
+4

En mi máquina esto produce el error 'Bareword' fgh 'no permitido mientras que' strict subs 'en uso en (eval 1) línea 1.' – Stephan202

+0

@ Stephan202, ¿cuál es su máquina? – nik

+0

Ubuntu 8.10 (perl v5.10.0/2009-06-26) – Stephan202

84

Esta es la forma en sed y mv se pueden utilizar juntos para hacer cambio de nombre:

for f in fgh*; do mv "$f" $(echo "$f" | sed 's/^fgh/jkl/g'); done 

Según comentario más abajo, si los nombres de archivo tengan espacios en ellos, las citas pueden necesitar envolvente la subfunción que devuelve el nombre para mover los archivos a:

for f in fgh*; do mv "$f" "$(echo $f | sed 's/^fgh/jkl/g')"; done 
+1

Muy cerca. Tenga en cuenta que solo desea hacer coincidir la primera aparición de fgh: 's/^ fgh/jkl/g' (El cursor marca la diferencia). – Stephan202

+2

Solo por el bien de la precisión ... Quiere decir "fgh al comienzo del nombre", no "la primera aparición de fgh"./^ fgh/coincidirá con "fghi", pero no con "efgh". –

+0

@Stephan, ese fue un error tipográfico de mi parte (lo solucionó). – nik

59

es posible que el cambio de nombre no esté en todos los sistemas. por lo que si no lo tiene, usar el intérprete este ejemplo en el shell bash

for f in fgh*; do mv "$f" "${f/fgh/xxx}";done 
+0

En esta solución, el comando 'sed' no es necesario. Esta es más simple que la respuesta de @ nik. – Halil

+0

xxx significa el reemplazo? en el caso del póster original, eso habría sido "jkl" – Awinad

+0

La solución más limpia de todas. –

17

Hay muchas maneras de hacerlo (no todos ellos trabajarán en todos los sistemas unixy):

  • ls | cut -c4- | xargs -I§ mv fgh§ jkl§

    El § puede sustituirse por cualquier elemento que considere conveniente. Se podría hacer esto con find -exec también, pero que se comporta de manera sutilmente diferente en muchos sistemas, por lo que suelen evitar que

  • for f in fgh*; do mv "$f" "${f/fgh/jkl}";done

    crudo pero efectivo como dicen

  • rename 's/^fgh/jkl/' fgh*

    bonito real, pero renombrar no está presente en BSD, que es el sistema unix más común afaik.

  • rename fgh jkl fgh*

  • ls | perl -ne 'chomp; next unless -e; $o = $_; s/fgh/jkl/; next if -e; rename $o, $_';

    Si usted insiste en el uso de Perl, pero no hay un cambio de nombre en su sistema, puede utilizar este monstruo.

Algunos de ellos son un poco complicado y la lista está lejos de ser completa, pero encontrará lo que usted quiere aquí para casi todos los sistemas UNIX.

+2

¡amo este tipo de monstruo! – lefakir

+0

sí, todavía tengo un punto débil para perl también :) – iwein

+0

tenga en cuenta que la salida ['ls' no se debe analizar y/o canalizar] (https://unix.stackexchange.com/q/128985/44425) –

3

Para instalar el script de Perl rename:

sudo cpan install File::Rename 

Hay two renames como se menciona en los comentarios en la respuesta de Stephan202. Las distribuciones basadas en Debian tienen el Perl rename. Las distribuciones Redhat/rpm tienen el C rename.
OS X no tiene una instalada por defecto (al menos en 10.8), tampoco Windows/Cygwin.

1

Aquí está una manera de hacerlo utilizando la línea de comandos maravilloso:

groovy -e 'new File(".").eachFileMatch(~/fgh.*/) {it.renameTo(it.name.replaceFirst("fgh", "jkl"))}' 
1

usando renamer (Windows, Mac y Linux amigable):

$ renamer --regex --find "^fgh" --replace "jkl" * 
2

yo recomendaría usar mi propio guión, que resuelve este problema También tiene opciones para cambiar la codificación de los nombres de los archivos y para convertir la combinación de diacríticos en caracteres precompuestos, un problema que siempre tengo cuando copio archivos de mi Mac.

https://github.com/kugland/rename.pl/blob/master/rename.pl

+1

Tenga en cuenta que [las respuestas solo de enlace] (http://meta.stackoverflow.com/tags/link-only-answers/info) no se recomiendan, por lo tanto, las respuestas deben ser el punto final de una búsqueda de una solución (vs. otra escala más de referencias, que tienden a quedar obsoletas en el tiempo). Considere agregar una sinopsis independiente aquí, manteniendo el enlace como referencia. – kleopatra

31

Usando mmv:

mmv "fgh*" "jkl#1" 
+1

¡Guau, esta es una manera excelente y simple de resolver el problema! Me alegro de ser presentado a mmv, gracias! – Hendeca

+1

Gracias! Nunca había oído hablar de mmv antes. Acabo de instalarlo y he estado jugando con él: simple, poderoso. –

+3

si desea cambiar el nombre del lote de forma recursiva use ';' junto con '# 1'. ejemplo: 'mmv"; fgh * "" # 1jkl # 2 "' – Alp

1

Usando StringSolver herramientas (Windows & Linux Bash), procedimiento que por ejemplos:

filter fghfilea ok fghreport ok notfghfile notok; mv --all --filter fghfilea jklfilea 

En primer lugar, calcula un filtro basado en ejemplos , donde la entrada es los nombres de archivo y la salida (ok y notok, cadenas arbitrarias). Si el filtro tuviera la opción --auto o se invocara solo después de este comando, crearía una carpeta ok y una carpeta notok y les insertaría archivos respectivamente.

Luego usando el filtro, el comando mv es un movimiento semiautomático que se convierte en automático con el modificador --auto. Usando el filtro anterior gracias a --filter, encuentra una asignación de fghfilea a jklfilea y luego lo aplica a todos los archivos filtrados.


Otras soluciones de una sola línea

Otras formas equivalentes de hacer lo mismo (cada línea es equivalente), para que pueda elegir su manera preferida de hacerlo.

filter fghfilea ok fghreport ok notfghfile notok; mv --filter fghfilea jklfilea; mv 
filter fghfilea ok fghreport ok notfghfile notok; auto --all --filter fghfilea "mv fghfilea jklfilea" 
# Even better, automatically infers the file name 
filter fghfilea ok fghreport ok notfghfile notok; auto --all --filter "mv fghfilea jklfilea" 

multi-paso de la solución

Para encontrar cuidadosamente si los comandos están funcionando bien, puede escribir lo siguiente:

filter fghfilea ok 
filter fghfileb ok 
filter fghfileb notok 

y cuando se tiene la certeza de que el filtro es bueno , realiza el primer movimiento:

mv fghfilea jklfilea 

Si desea probar y usar el filtro anterior, escriba:

mv --test --filter 

Si la transformación no es lo que quería (por ejemplo, incluso con mv --explain se ve que algo está mal), puede escribir mv --clear para reiniciar mover archivos, o añadir más ejemplos mv input1 input2 donde INPUT1 y INPUT2 son otros ejemplos

Cuando esté seguro, sólo tiene que escribir

mv --filter 

¡y voilá! Todo el cambio de nombre se hace usando el filtro.

DESCARGO DE RESPONSABILIDAD: Yo soy coautor de este trabajo hecho con fines académicos. También podría haber una función de producción de bashs pronto.

1

Fue mucho más fácil (en mi Mac) hacer esto en Ruby. Aquí hay 2 ejemplos:

# for your fgh example. renames all files from "fgh..." to "jkl..." 
files = Dir['fgh*'] 

files.each do |f| 
    f2 = f.gsub('fgh', 'jkl') 
    system("mv #{f} #{f2}") 
end 

# renames all files in directory from "021roman.rb" to "021_roman.rb" 
files = Dir['*rb'].select {|f| f =~ /^[0-9]{3}[a-zA-Z]+/} 

files.each do |f| 
    f1 = f.clone 
    f2 = f.insert(3, '_') 
    system("mv #{f1} #{f2}") 
end 
6

Usando find, xargs y sed:

find . -name "fgh*" -type f -print0 | xargs -0 -I {} sh -c 'mv "{}" "$(dirname "{}")/`echo $(basename "{}") | sed 's/^fgh/jkl/g'`"' 

Es más complejo que @nik's solution pero permite renombrar archivos de forma recursiva. Por ejemplo, la estructura,

. 
├── fghdir 
│   ├── fdhfilea 
│   └── fghfilea 
├── fghfile\ e 
├── fghfilea 
├── fghfileb 
├── fghfilec 
└── other 
    ├── fghfile\ e 
    ├── fghfilea 
    ├── fghfileb 
    └── fghfilec 

se transformaría a esto,

. 
├── fghdir 
│   ├── fdhfilea 
│   └── jklfilea 
├── jklfile\ e 
├── jklfilea 
├── jklfileb 
├── jklfilec 
└── other 
    ├── jklfile\ e 
    ├── jklfilea 
    ├── jklfileb 
    └── jklfilec 

La clave para hacer que funcione con xargs es invoke the shell from xargs.

+1

Iba a publicar algo como esto, pero me hubiera llevado una hora obtener el comando correcto –

2
#!/bin/sh 

#replace all files ended witn .f77 to .f90 in a directory 

for filename in *.f77 

do 

    #echo $filename 
    #b= echo $filename | cut -d. -f1 
    #echo $b  
    mv ${filename} ${filename%.f77}.f90 

#print $? 

done 
2

Mi versión de renombrar archivos en masa:

for i in `ls`; do (echo mv $i $i) ; done > result.txt 
cat result.txt | sed -e "s#from_pattern#to_pattern#g” > result1.sh 
sh result1.sh 
+0

Me gusta la capacidad de verificar antes de ejecutar el script – ardochhigh

3

En Solaris que puede probar:

for file in `find ./ -name "*TextForRename*"`; do 
    mv -f "$file" "${file/TextForRename/NewText}" 
done 
0

Esto funcionó para mí usando expresiones regulares:

quería archivos sean renombrado de esta manera:

file0001.txt -> 1.txt 
ofile0002.txt -> 2.txt 
f_i_l_e0003.txt -> 3.txt 

use el [a-z | _] + 0 * ([0-9] +. ) regexp donde ([0-9] +.) es una subcadena grupo a usar en el comando de cambio de nombre

ls -1 | awk 'match($0, /[a-z|\_]+0*([0-9]+.*)/, arr) { print arr[0] " " arr[1] }'|xargs -l mv 

Produce:

mv file0001.txt 1.txt 
mv ofile0002.txt 2.txt 
mv f_i_l_e0003.txt 3.txt 

Otro ejemplo:

file001abc.txt -> abc1.txt 
ofile0002abcd.txt -> abcd2.txt 

ls -1 | awk 'match($0, /[a-z|\_]+0*([0-9]+.*)([a-z]+)/, arr) { print arr[0] " " arr[2] arr[1] }'|xargs -l mv 

Produce:

mv file001abc.txt abc1.txt 
    mv ofile0002abcd.txt abcd2.txt 

Warning, sea cuidadoso.

0

Escribí este script para buscar todos los archivos .mkv recursivamente cambiando el nombre de los archivos encontrados a .avi. Puede personalizarlo para sus necesidades. He agregado algunas otras cosas como obtener el directorio de archivos, la extensión, el nombre de archivo de una ruta de archivo en caso de que necesite consultar algo en el futuro.

find . -type f -name "*.mkv" | while read fp; do 
fd=$(dirname "${fp}"); 
fn=$(basename "${fp}"); 
ext="${fn##*.}"; 
f="${fn%.*}"; 
new_fp="${fd}/${f}.avi" 
mv -v "$fp" "$new_fp" 
done; 
0

Una secuencia de comandos genérico para ejecutar una expresión sed en una lista de archivos (combina la sed solution con el rename solution):

#!/bin/sh 

e=$1 
shift 

for f in $*; do 
    fNew=$(echo "$f" | sed "$e") 
    mv "$f" "$fNew"; 
done 

invocación al pasar el guión una expresión sed, y luego cualquier lista de archivos, al igual que una versión de rename:

script.sh 's/^fgh/jkl/' fgh* 
0

también puede utilizar a continuación guión. es muy fácil de ejecutar en el terminal ...

// Cambiar el nombre de varios archivos a la vez

for file in FILE_NAME* 
do 
    mv -i "${file}" "${file/FILE_NAME/RENAMED_FILE_NAME}" 
done 

Ejemplo: -

for file in hello* 
do 
    mv -i "${file}" "${file/hello/JAISHREE}" 
done 
Cuestiones relacionadas