Cambie el nombre de varios archivos con mv para cambiar la extensión

27

Quiero cambiar el nombre de los archivos para cambiar su extensión, buscando efectivamente lograr

mv *.txt *.tsv

Pero al hacer esto obtengo:

* .tsv no es un directorio

Me resulta un tanto extraño que los primeros 10 éxitos de Google Show mvfuncionen así.

Sander Van der Zeeuw
fuente
Debe explicar cómo desea cambiar el nombre de esos archivos exactamente.
Totor
1
Bueno, tengo archivos con una extensión de * .gappedPeak y quiero cambiarles el nombre a * .bed. todos están en el mismo directorio, debería ser muy simple, pero se necesitaba un ciclo completo para que yo tuviera éxito
Sander Van der Zeeuw
Lo que encontraste en Google se aplica a MSDOS, creo.
tiktak
La solución alternativa de @devnull es realmente útil
lucasvw

Respuestas:

22

Cuando emite el comando:

mv *.txt *.tsv

el shell, supongamos que bash, expande los comodines si hay archivos coincidentes (incluidos los directorios). La lista de archivos se pasa al programa, aquí mv. Si no se encuentran coincidencias, se pasa la versión no expandida.

Nuevamente: el shell expande los patrones, no el programa.


Un montón de ejemplos es quizás la mejor manera, así que aquí vamos:

Ejemplo 1:

$ ls
file1.txt file2.txt

$ mv *.txt *.tsv

Ahora lo que sucede en la mvlínea es que el shell se expande *.txta los archivos coincidentes. Como no hay *.tsvarchivos que no se modifiquen.

El mvcomando se llama con dos argumentos especiales :

  • argc: Número de argumentos, incluido el programa.
  • argv: Una matriz de argumentos, incluido el programa como primera entrada.

En el ejemplo anterior sería:

 argc = 4
 argv[0] = mv
 argv[1] = file1.txt
 argv[2] = file2.txt
 argv[3] = *.tsv

El mvprograma verifica si el último argumento *.tsv, es un directorio. Como no es así, el programa no puede continuar ya que no está diseñado para concatenar archivos. (Por lo general, mueva todos los archivos a uno). Tampoco cree directorios por capricho.

Como resultado, aborta e informa el error:

mv: target ‘*.tsv’ is not a directory

Ejemplo 2

Ahora si en cambio dices:

$ mv *1.txt *.tsv

El mvcomando se ejecuta con:

 argc = 3
 argv[0] = mv
 argv[1] = file1.txt
 argv[2] = *.tsv

Ahora, nuevamente, mvverifique si *.tsvexiste. Como no lo hace, el archivo file1.txtse mueve a *.tsv. Es decir: el archivo se renombra *.tsvcon el asterisco y todo.

$ mv *1.txt *.tsv
‘file1.txt’ -> ‘*.tsv’

$ ls
file2.txt *.tsv

Ejemplo 3

Si en cambio dijiste:

$ mkdir *.tsv
$ mv *.txt *.tsv

El mvcomando se ejecuta con:

 argc = 3
 argv[0] = mv
 argv[1] = file1.txt
 argv[1] = file2.txt
 argv[2] = *.tsv

Como *.tsvahora es un directorio, los archivos terminan siendo movidos allí.


Ahora: usando comandos como some_command *.tsvcuando la intención es mantener el comodín, uno siempre debe citarlo. Al citar, evita que los comodines se expandan si hubiera coincidencias. Por ejemplo, decir mkdir "*.tsv".

Ejemplo 4

La expansión se puede ver aún más si lo hace, por ejemplo:

$ ls
file1.txt file2.txt

$ mkdir *.txt
mkdir: cannot create directory ‘file1.txt’: File exists
mkdir: cannot create directory ‘file2.txt’: File exists

Ejemplo 5:

Ahora: el mvcomando puede y funciona en varios archivos. Pero si hay más de dos, el último debe ser un directorio de destino. (Opcionalmente, puede usar la -t TARGET_DIRopción, al menos para GNU mv.)

Entonces esto está bien:

$ ls -F
b1.tsv  b2.tsv  f1.txt  f2.txt  f3.txt  foo/

$ mv *.txt *.tsv foo

Aquí mvse llamaría con:

 argc = 7
 argv[0] = mv
 argv[1] = b1.tsv
 argv[2] = b2.tsv
 argv[3] = f1.txt
 argv[4] = f2.txt
 argv[5] = f3.txt
 argv[6] = foo

y todos los archivos terminan en el directorio foo.


En cuanto a tus enlaces. Ha proporcionado uno (en un comentario), donde mvno se menciona en absoluto, pero rename. Si tiene más enlaces que podría compartir. Así como para las páginas de manual donde usted afirma que esto se expresa.

Runium
fuente
30

Sé que esto no responde a su pregunta, pero en caso de que estuviera buscando otra forma de cambiar el nombre de los archivos en comparación con su ciclo de solución, ¿por qué no usarlo find? He usado este comando muchas veces para reemplazar extensiones de archivo en directorios grandes con cientos de miles de archivos en él. Esto debería funcionar en cualquier sistema compatible con POSIX:

find . -name "*.gappedPeak" -exec sh -c 'mv "$1" "${1%.gappedPeak}.bed"' _ {} \;

Desglose de comandos:

  1. ' .' => ruta de búsqueda que comienza en el directorio actual marcado por '. '

  2. -name=> establecer el nombre de buscar coincidencia (en este caso, todos los archivos que terminan con .gappedPeak)

  3. -exec => ejecuta el siguiente comando en cada partida

  4. sh -c => 'exec' crea un entorno de shell independiente para cada coincidencia

  5. mv "$1" "${1%.gappedPeak}.bed"=> mvprimera variable (denotada por $ 1 ), que es el nombre del archivo actual, al nuevo nombre. Aquí hago una coincidencia de subcadena y elimino; así que tome la primera var nuevamente, $ 1 y úsela %para eliminar .gappedPeakde la cadena. El .bedal final simplemente concatena la variable restante, que ahora es sólo , con , creando el nuevo nombre de archivo.test#.bedtest#.bed

  6. El guión bajo es un marcador de posición por $ 0

  7. El {}es reemplazado por cada ( *.gappedPeak) nombre de archivo encontrado por el findcomando, y se convierte en $ 1 para el shcomando.

  8. \;marca el final del -execcomando. También puedes usar ';'o ";".

Ejemplo:

[user@before]# ls -lh
total 0
-rw-r--r--. 1 root root 0 Jan 26 11:40 test1.gappedPeak
-rw-r--r--. 1 root root 0 Jan 26 11:40 test2.gappedPeak
-rw-r--r--. 1 root root 0 Jan 26 11:40 test3.gappedPeak
-rw-r--r--. 1 root root 0 Jan 26 11:40 test4.gappedPeak
-rw-r--r--. 1 root root 0 Jan 26 11:40 test5.gappedPeak

[user@after]# ls -lh
total 0
-rw-r--r--. 1 root root 0 Jan 26 11:40 test1.bed
-rw-r--r--. 1 root root 0 Jan 26 11:40 test2.bed
-rw-r--r--. 1 root root 0 Jan 26 11:40 test3.bed
-rw-r--r--. 1 root root 0 Jan 26 11:40 test4.bed
-rw-r--r--. 1 root root 0 Jan 26 11:40 test5.bed
devnull
fuente
¿Podría pasar por el comando que describe lo que hace cada parte?
user1717828
Lo siento, actualicé mi publicación. Espero que ayude.
devnull
1
¡Genial gracias! Con una guía de bash y tu explicación pude obtener todo.
user1717828
No hay problema. Me alegra que ayude.
devnull
Funciona de maravilla. Aquí hay otro ejemplo simplificado para file.abc-> blub.xyzen múltiples subdirectorios:find . -name "file.abc" -exec sh -c 'mv "$1" "$(dirname $1)/blub.xyz"' _ {} \;
Mahn
9

mv *.txt *.tsvno funciona mvsolo puede cambiar el nombre de un archivo a la vez. Has entendido mal las explicaciones o están equivocadas.

mmvy renamepuede cambiar el nombre de varios archivos a la vez. Pero hay dos versiones de renamealrededor que se llaman de manera diferente. Debería haber muchas preguntas sobre eso aquí.

Hauke ​​Laging
fuente
1
cyberciti.biz/tips/... El primer éxito de Google está diciendo que debería funcionar como mv eso es así por qué me pareció tan extraño
Sander Van der Zeeuw
3
@SanderVanderZeeuw No sé lo que lees allí. Los ejemplos usan rename, no mv.
Hauke ​​Laging
1
lo siento, pegué el HTML incorrecto. Este fue el udemy.com/blog/rename-a-file-in-linux
Sander Van der Zeeuw
3
@SanderVanderZeeuw Vergonzoso. Estas personas ofrecen cursos? Lamentablemente no veo una posibilidad de contacto allí. Puede verificar fácilmente si esto funciona. Pero en mv *.txt *.tsv mv(por lo general) no se ve *.txtni *.tsvlos nombres de archivo expandidos por shell. El número de archivos a los que se expanden estos comodines sería "aleatorio". La única situación en la que esto funciona es si hay un archivo con el nombre *.txtque será renombrado (literalmente) *.tsv(sin citar la bashopción nullglobno debe establecerse).
Hauke ​​Laging
1
O peor. Si uno tiene un archivo llamado por ejemplo, foo.txty uno nombrado baz.tsvel mv *.txt *.tsvhará que la carpeta .tsvde archivos ...
Runium
4

Por ejemplo, si usted tiene asd.txty qwe.txtarchivos en el directorio cuando se ejecuta el comando mv *.txt *.tsv, se trata de mover estos dos archivos en un directorio llamado *.tsv. Debido a que no existe tal directorio, da un error.

Esref
fuente
Gracias, esto se aclara parcialmente. Aún así, me parece extraño que vea tantas páginas de manual donde afirman que mv debería funcionar en múltiples.
Sander Van der Zeeuw
2

rename(1)

renamees un guión perl de Larry Wall, el creador de perl. Toma una expresión regular Perl y opera en el nombre del archivo.

rename 's/\.txt$/.tsv/' *.txt

Instalación

Debian / Ubuntu

Si necesita instalar renameen Debian / Ubuntu, puede hacerlo

sudo apt install rename
Evan Carroll
fuente
0

Otra opción a considerar es usar:

cp -p *.txt *.tsv
rm -f *.txt
  • La primera línea copia todos los *.txtarchivos *.tsvmientras conserva sus atributos usando la -pbandera.
  • La segunda línea elimina todos los archivos con el patrón. *.txt
  • Este método requiere que tenga suficiente espacio en disco para contener temporalmente los archivos de origen y destino
  • Este método es más lento que el mvque simplemente cambia el / directorio / nombre de archivo sin mover realmente los archivos a menos que estén en una partición diferente.
WinEunuuchs2Unix
fuente