Linux: ¿cambiar el nombre del archivo pero mantener la extensión?

10

En Windows / DOS, puedo decir rename myfile.* yourfile.*que cambie el nombre pero mantenga la extensión. ¿Cómo se logra eso en Linux?

La página de manual solo sugiere cómo cambiar la extensión, pero eso es lo contrario de lo que quiero.

Bonificación: en
realidad quiero poner la fecha de creación de una foto en su nombre de archivo, para obtener algo así 20091231 2359 New Year.jpg. ¿Me temo que necesito una combinación no trivial de comandos para lograr eso?

Torben Gundtofte-Bruun
fuente

Respuestas:

14

Aquí hay una respuesta para la pregunta extra.

De hecho, quiero poner la fecha de creación de una foto en su nombre de archivo, para obtener algo como 20091231 2359 New Year.jpg. ¿Me temo que necesito una combinación no trivial de comandos para lograr eso?

Suponiendo que desea tomar la fecha de creación de la foto a partir de los datos EXIF, necesitará una herramienta separada para eso. Afortunadamente resulta que jheadofrece una forma trivial de hacer exactamente lo que quieres, con su -nopción.

$ jhead -h
 [...]

 -n[format-string]

             Rename files according to date.  Uses exif date if present, file
             date otherwise.  If the optional format-string is not supplied,
             the format is mmdd-hhmmss.  If a format-string is given, it is
             is passed to the 'strftime' function for formatting
             In addition to strftime format codes:
             '%f' as part of the string will include the original file name
             [...]

Aquí hay un ejemplo:

$ jhead -n%Y-%m-%d-%f New_year.jpg   
New_year.jpg --> 2009-12-31-New_year.jpg

Editar : Por supuesto, para hacer esto por un montón de fotos, sería algo como:

$ for i in *jpg; do jhead -n%Y-%m-%d-%f $i; done

Para ajustar el formato de fecha a su gusto, eche un vistazo a la salida de date --help, por ejemplo; enumerará los códigos de formato disponibles.

(jhead está ampliamente disponible para diferentes sistemas. Si está, por ejemplo, en Ubuntu o Debian, simplemente escriba sudo apt-get install jheadpara instalarlo).

Jonik
fuente
1
No había pensado en jhead, solo en una fea combinación de cambio de nombre, estadística y corte. Gracias por la gran respuesta!
Torben Gundtofte-Bruun
10

Solo por la parte de cambio de nombre, el programa 'renombrar' funcionará. Es el mismo que el ejemplo que viste en la página del manual, que acaba de cambiar.

justin@eee:/tmp/q$ touch myfile.{a,b,c,d}
justin@eee:/tmp/q$ ls
myfile.a  myfile.b  myfile.c  myfile.d
justin@eee:/tmp/q$ rename -v s/myfile/yourfile/ myfile.*
myfile.a renamed as yourfile.a
myfile.b renamed as yourfile.b
myfile.c renamed as yourfile.c
myfile.d renamed as yourfile.d
justin@eee:/tmp/q$ ls
yourfile.a  yourfile.b  yourfile.c  yourfile.d
justin@eee:/tmp/q$ 
usuario23307
fuente
1
En algunas distribuciones, este programa de cambio de nombre de perl se llama prename.
camh
¡Esto es realmente útil! Me sorprendió la cantidad de preguntas que tenía que buscar antes de encontrar "cambiar el nombre". Gracias.
alanning
7
betelgeuse:tmp james$ ls myfile.* yourfile.*
ls: yourfile.*: No such file or directory   
myfile.a    myfile.b
betelgeuse:tmp james$ for file
> in myfile.*
> do
> mv "${file}" "`echo $file | sed 's/myfile\./yourfile./'`"
> done
betelgeuse:tmp james$ ls myfile.* yourfile.*
ls: myfile.*: No such file or directory
yourfile.a  yourfile.b

La clave es que, si ha visto un ejemplo que muestra cómo combinar una parte del nombre de archivo con una expresión regular, ese es el único ejemplo que necesita. Las extensiones no tienen un estado especial en los sistemas de archivos Unix: son solo una parte del nombre de archivo que aparece después de un .carácter.

James Polley
fuente
1
Esta es la respuesta a mi pregunta. (Pero la otra respuesta me lleva allí más rápido y más fácil.)
Torben Gundtofte-Bruun
44
No hay necesidad de tenedor + exec sed: mv "$file" yourfile"${file#myfile}". Funciona en cualquier shell moderno similar a Bourne (o en cualquier shell POSIX), pero probablemente no en el shell Bourne real.
Chris Johnsen
4

Aquí hay un par de formas diferentes de manipular nombres de archivos

for f in *.jpg
do
    mv "$f" "before_part${f%.*}after_part.${f##*.}"
    # OR mv "$f" "before_part$(basename "$f" ".jpg")after_part.jpg"
done

Las expansiones de parámetros en el mvcomando funcionan de la siguiente manera:

${f%.*}- Elimine el patrón de coincidencia más corto desde el final de la cadena contenida $f, en este caso elimine todo después e incluyendo el último punto. El single %significa "el más corto desde el final".

${f##*.}- Elimine el patrón de coincidencia más largo desde el principio de la cadena contenida $f, en este caso, todo lo anterior e incluido el último punto (esto incluye también otros puntos). El doble #( ##) significa "el más largo desde el principio".

Entonces, por ejemplo, si $fcontiene "Foo.bar.baZ.jpg":

echo "${f%.*}"

da

Foo.bar.baZ

y

echo "${f##*.}"

da

jpg

Entonces el mvcomando, una vez expandido, se vería así:

mv "Foo.bar.baZ.jpg" "before_partFoo.bar.baZafter_part.jpg"
Dennis Williamson
fuente
De hecho, terminé usando el bucle FOR pero no el ejemplo de MV porque no lo entiendo :-)
Torben Gundtofte-Bruun
Nota: El significado de esos f%y f##se describen aquí, por ejemplo: tldp.org/LDP/abs/html/parameter-substitution.html
Torben Gundtofte-Bruun
3

No hay extensiones de nombre de archivo en Linux.

Use expresiones regulares para cortar subcadenas particulares del nombre de archivo y acceder a ellas.

Ejemplo:

Escenario de la vida real: está extrayendo html de un archivo chm. Los nombres de archivo en Windows no distinguen entre mayúsculas y minúsculas, por lo que en Linux obtendrá enlaces rotos. Tiene un archivo llamado index.HTML , pero href = "index.html" en las URL. Por lo tanto, su objetivo es adaptar los nombres de archivo para que coincidan con los enlaces a ellos.

Suponga que tiene el nombre de archivo en una variable:

FILENAME='index.HTML'

A partir de la versión 3.0, bash admite expresiones regulares en sí, por lo que no necesita herramientas adicionales como grep / sed / perl, etc. para realizar la manipulación de cadenas. El siguiente ejemplo ilustra el reemplazo de una coincidencia de fondo en una cadena:

echo ${FILENAME/%\.HTML/.html}

Las cadenas de coincidencia y reemplazo se pueden parametrizar si lo desea, esto proporciona flexibilidad adicional al escribir guiones. El siguiente fragmento de código logra el mismo objetivo:

match='\.HTML'
replacement='.html'
echo ${FILENAME/%$match/$replacement}

Consulte los documentos de bash para obtener información adicional.

friki
fuente
1
¿Algún ejemplo en estas expresiones regulares?
Gnoupi
+1. Esta respuesta es muy útil ahora (después de la edición): no tenía idea de que puede hacer tal manipulación de cadenas en Bash.
Jonik
De hecho, mucho mejor ahora, con ejemplos. +1
Gnoupi
0

Aquí está otro:

find -name "*.jpg" -printf '"%p" "%h/%TY%Tm%Td %TH%TM %f"\n' | while read -r f
do
    eval "mv ${f}"
done
Dennis Williamson
fuente
0

Siempre hay más de una forma de hacerlo. Puse el siguiente script como / usr / local / bin / mrename.

Luego, en el script que contiene los archivos de fotos, simplemente escriba: mrename

También hay una función opcional comentada en el script para escalar las fotos (usando ImageMagick).

Espero que esto sea útil para algunas personas.

#!/usr/bin/perl
#
# mrename files
#
#
use strict;

# if no 2 args, use defaults
my $dir = ".";

# read in path from command line
$dir = $ARGV[0] if ( defined( $ARGV[0] ) && $ARGV[0] ne "" );

# read in directory contents
opendir( DIR, $dir );
my @files = readdir( DIR );
closedir( DIR );

# rename and/or scale each file in directory
my $number_of_files = scalar( @files );
my $curfile = 0;

foreach my $file( @files ) {
    # only rename and scale jpg/gif files
    if ( $file =~ /\w+\.(jpg)$/ ) {
        my $extension = $1;
        $extension =~ tr/A-Z/a-z/;
        my $full_filename = "$dir/$file";

        # get stats on file- specifically the last modified time
        (my $dev,my $ino,my $mode,my $nlink,my $uid,my $gid,my $rdev,my $size,
        my $atime,my $mtime,my $ctime,my $blksize,my $blocks) = stat($full_filename);

        # convert last-modified time from seconds to practical datetime terms
        (my $sec,my $min,my $hour,my $mday,my $mon,my $year,my $wday,my $yday,
        my $isdst) = localtime($mtime);

        ++$mon;
        $year += 1900;

        my $filecdate = sprintf( "m%04i%02i%02i_%02i%02i%02i.$extension", $year, $mon, $mday, $hour, $min, $sec );
        my $full_newfilename = "$dir/$filecdate";

        # to scale files, use imagemagick by using the command below instead of mv 
        #my $cmd = "convert $full_filename -resize $scale% $full_newfilename";
        my $cmd = "mv $full_filename $full_newfilename";
        system( $cmd );

        # update percentage done
        my $percent_done = sprintf( "%5.2lf", 100* (++$curfile) / $number_of_files );
        print "\r$percent_done%";
    }
}
print "\n";

fuente
0

Puede usar la -X/--keep-extensionopción con rename(versión 1.600):

-X, --keep-extension Save and remove the last extension from a filename, if there is any. The saved extension will be appended back to the filename at the end of the rest of the operations.

rename está disponible para Mac de Homebrew y para Linux de Linuxbrew (entre otras opciones de instalación, por supuesto).

John
fuente