Linux: rinominare il file ma mantenere l'estensione?


10

In Windows / DOS, posso dire rename myfile.* yourfile.*di cambiare il nome ma mantenere l'estensione. Come si ottiene ciò su Linux?

La pagina man suggerisce solo come modificare l'estensione, ma è l'opposto di quello che voglio.

Bonus:
In realtà voglio mettere la data di creazione di una foto nel suo nome file, per ottenere qualcosa del genere 20091231 2359 New Year.jpg. Temo di aver bisogno di una combinazione non banale di comandi per raggiungere questo obiettivo?

Risposte:


14

Ecco una risposta per la domanda bonus.

In realtà voglio mettere la data di creazione di una foto nel suo nome file, per ottenere qualcosa come 20091231 2359 New Year.jpg. Temo di aver bisogno di una combinazione non banale di comandi per raggiungere questo obiettivo?

Supponendo che tu voglia prendere la data di creazione della foto dai dati EXIF, avrai bisogno di uno strumento separato per quello. Fortunatamente si scopre che jheadoffre un modo banale per fare esattamente quello che vuoi, con la sua -nopzione.

$ 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
             [...]

Ecco un esempio:

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

Modifica : naturalmente, per fare questo per un mucchio di foto, sarebbe qualcosa di simile:

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

Per modificare la formattazione della data a tuo piacimento, dai un'occhiata all'output di date --help, ad esempio; elencherà i codici di formato disponibili.

(jhead è ampiamente disponibile per diversi sistemi. Se ad esempio sei su Ubuntu o Debian, digita semplicemente sudo apt-get install jheadper installarlo.)


1
Non avevo pensato a jhead, ma solo a una brutta combinazione di rinomina, stat e taglio. Grazie per l'ottima risposta!
Torben Gundtofte-Bruun,

10

Solo per la parte che rinomina, il programma "rinomina" funzionerà. È lo stesso dell'esempio che hai visto nella pagina man, appena cambiato.

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$ 

1
In alcune distro, questo programma per rinominare il perl è chiamato prename.
Camh

Questo è davvero utile! Sono stato sorpreso da quanti di questi tipi di domande ho dovuto cercare prima di trovare "rinomina". Grazie.
dal

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 chiave è che, se hai visto un esempio che mostra come trasferire una parte del nome file con una regex, questo è l'unico esempio di cui hai bisogno. Le estensioni non hanno uno stato speciale sui filesystem unix: sono solo una parte del nome file che si trova dopo un .carattere.


1
Questa è la risposta alla mia domanda. (Ma l'altra risposta mi porta lì più velocemente e più facilmente.)
Torben Gundtofte-Bruun

4
Non c'è bisogno di fork + exec sed: mv "$file" yourfile"${file#myfile}". Funziona su qualsiasi moderna shell tipo Bourne (o qualsiasi shell POSIX), ma probabilmente non l'attuale shell Bourne.
Chris Johnsen,

4

Qui ci sono un paio di modi diversi per manipolare i nomi dei file

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

Le espansioni dei parametri nel mvcomando funzionano come segue:

${f%.*}- Elimina il modello di corrispondenza più breve dalla fine della stringa contenuta in $f, in questo caso elimina tutto dopo e incluso l'ultimo punto. Il singolo %significa "il più corto dalla fine".

${f##*.}- Elimina il motivo di corrispondenza più lungo dall'inizio della stringa contenuta $f, in questo caso tutto prima e incluso l'ultimo punto (inclusi anche tutti gli altri punti). Il doppio #( ##) significa "il più lungo dall'inizio".

Ad esempio, se $fcontiene "Foo.bar.baZ.jpg":

echo "${f%.*}"

Foo.bar.baZ

e

echo "${f##*.}"

jpg

Quindi il mvcomando, una volta espanso, sarebbe simile a:

mv "Foo.bar.baZ.jpg" "before_partFoo.bar.baZafter_part.jpg"

In realtà ho finito per usare il ciclo FOR ma non l'esempio MV perché non lo capisco :-)
Torben Gundtofte-Bruun,

Nota: il significato di questi f%e f##sono descritti qui, ad esempio: tldp.org/LDP/abs/html/parameter-substitution.html
Torben Gundtofte-Bruun,

3

Non ci sono estensioni di file in Linux.

Usa le espressioni regolari per tagliare particolari sottostringhe dal nome del file e accedervi.

Esempio:

Scenario di vita reale: stai estraendo html da un file chm. I nomi di file in Windows non fanno distinzione tra maiuscole e minuscole, quindi in Linux otterrai collegamenti interrotti. Hai un file chiamato index.HTML , ma href = "index.html" negli URL. Quindi il tuo obiettivo è quello di adattare i nomi dei file per abbinare i collegamenti a loro.

Supponiamo di avere il nome file in una variabile:

FILENAME='index.HTML'

A partire dalla versione 3.0 bash supporta le espressioni regolari, quindi non è necessario alcuno strumento aggiuntivo come grep / sed / perl ecc per eseguire la manipolazione delle stringhe. L'esempio seguente mostra la sostituzione di una corrispondenza back-end in una stringa:

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

Le stringhe di corrispondenza e sostituzione possono essere parametrizzate se lo si desidera, ciò fornisce ulteriore flessibilità durante la scrittura di script. Il seguente frammento di codice raggiunge lo stesso obiettivo:

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

Consultare i documenti di bash per ulteriori informazioni.


1
Qualche esempio, su queste espressioni regolari?
Gnoupi,

+1. Questa risposta è molto utile ora (dopo la modifica) - Non avevo idea che tu possa fare una tale manipolazione delle stringhe in Bash.
Jonik,

Anzi, molto meglio ora, con esempi. +1
Gnoupi,


0

C'è sempre più di un modo per farlo. Ho messo il seguente script come / usr / local / bin / mrename.

Quindi nello script contenente i file di foto, basta digitare: mrename

C'è anche una funzione opzionale commentata nello script per ridimensionare le foto (usando ImageMagick).

Spero che questo sia utile per alcune persone.

#!/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";

0

È possibile utilizzare l' -X/--keep-extensionopzione con rename(versione 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 è disponibile per Mac da Homebrew e per Linux da Linuxbrew (tra le altre opzioni di installazione ovviamente).

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.