Linux: renommer le fichier mais conserver l'extension?

10

Sous Windows / DOS, je peux dire rename myfile.* yourfile.*de changer le nom mais garder l'extension. Comment cela se fait-il sous Linux?

La page de manuel suggère seulement comment changer l'extension, mais c'est l'opposé de ce que je veux.

Bonus:
je veux en fait mettre la date de création d'une photo dans son nom de fichier, pour obtenir quelque chose comme 20091231 2359 New Year.jpg. J'ai peur d'avoir besoin d'une combinaison de commandes non triviale pour y parvenir?

Torben Gundtofte-Bruun
la source

Réponses:

14

Voici une réponse à la question bonus.

En fait, je veux mettre la date de création d'une photo dans son nom de fichier, pour obtenir quelque chose comme 20091231 2359 New Year.jpg. J'ai peur d'avoir besoin d'une combinaison de commandes non triviale pour y parvenir?

En supposant que vous souhaitez prendre la date de création de la photo à partir des données EXIF, vous aurez besoin d'un outil distinct pour cela. Heureusement, il s'avère que cela jheadoffre un moyen trivial de faire exactement ce que vous voulez, avec son -noption.

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

Voici un exemple:

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

Edit : Bien sûr, pour faire cela pour un tas de photos, ce serait quelque chose comme:

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

Pour modifier la mise en forme de la date à votre guise, jetez un œil à la sortie de date --help, par exemple; il répertorie les codes de format disponibles.

(jhead est largement disponible pour différents systèmes. Si vous êtes par exemple sur Ubuntu ou Debian, tapez simplement sudo apt-get install jheadpour l'installer.)

Jonik
la source
1
Je n'avais pas pensé à jhead, seulement à une combinaison laide de rename, stat et cut. Merci pour la bonne réponse!
Torben Gundtofte-Bruun
10

Pour juste la partie renommée, le programme «renommer» fonctionnera. C'est la même chose que l'exemple que vous avez vu dans la page de manuel, juste changé.

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$ 
user23307
la source
1
Sur certaines distributions, ce programme de changement de nom perl est appelé prename.
camh
C'est vraiment utile! J'ai été surpris par le nombre de ces types de questions que j'ai dû parcourir avant de trouver "renommer". Je vous remercie.
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 clé est que, si vous avez vu un exemple qui montre comment fusionner une partie du nom de fichier avec une expression régulière, c'est le seul exemple dont vous avez besoin. Les extensions n'ont pas de statut spécial sur les systèmes de fichiers Unix - elles ne sont qu'une partie du nom de fichier qui se trouve être après un .caractère.

James Polley
la source
1
Ceci est la réponse à ma question. (Mais l'autre réponse me permet d'y
arriver
4
Pas besoin de fourchette + exec sed: mv "$file" yourfile"${file#myfile}". Fonctionne sur n'importe quel shell Bourne moderne (ou sur n'importe quel shell POSIX), mais probablement pas sur le shell Bourne réel.
Chris Johnsen
4

Voici quelques façons différentes de manipuler les noms de fichiers

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

Les extensions de paramètres dans la mvcommande fonctionnent comme suit:

${f%.*}- Supprimez le motif de correspondance le plus court de la fin de la chaîne contenue dans $f, dans ce cas, supprimez tout après et y compris le dernier point. Le single %signifie "le plus court de la fin".

${f##*.}- Supprimez le motif de correspondance le plus long depuis le début de la chaîne contenue dans $f, dans ce cas, tout ce qui précède et inclut le dernier point (cela inclut également les autres points). Le double #( ##) signifie "le plus long depuis le début".

Ainsi, par exemple, si $fcontient "Foo.bar.baZ.jpg":

echo "${f%.*}"

donne

Foo.bar.baZ

et

echo "${f##*.}"

donne

jpg

Ainsi, la mvcommande, une fois développée, ressemblerait à:

mv "Foo.bar.baZ.jpg" "before_partFoo.bar.baZafter_part.jpg"
En pause jusqu'à nouvel ordre.
la source
En fait, j'ai fini par utiliser la boucle FOR mais pas l'exemple MV parce que je ne le comprends pas :-)
Torben Gundtofte-Bruun
Remarque: La signification de ceux-ci f%et f##sont décrits ici, par exemple: tldp.org/LDP/abs/html/parameter-substitution.html
Torben Gundtofte-Bruun
3

Il n'y a aucune extension de nom de fichier sous Linux.

Utilisez des expressions régulières pour couper des sous-chaînes particulières du nom de fichier et y accéder.

Exemple:

Scénario réel: vous extrayez du HTML à partir d'un fichier chm. Les noms de fichiers sous Windows ne sont pas sensibles à la casse, donc sous Linux, vous obtiendrez des liens rompus. Vous avez un fichier nommé index.HTML , mais href = "index.html" dans les URL. Votre objectif est donc d'adapter les noms de fichiers pour qu'ils correspondent aux liens.

Supposons que vous ayez le nom de fichier dans une variable:

FILENAME='index.HTML'

À partir de la version 3.0, bash prend en charge les expressions régulières lui-même, vous n'avez donc pas besoin d'outils supplémentaires comme grep / sed / perl, etc. pour effectuer une manipulation de chaîne. L'exemple suivant illustre le remplacement d'une correspondance principale dans une chaîne:

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

La correspondance et les chaînes de remplacement peuvent être paramétrées si vous le souhaitez, cela offre une flexibilité supplémentaire lors de l'écriture du script. L'extrait de code suivant atteint le même objectif:

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

Consultez les documents bash pour plus d'informations.

geek
la source
1
Un exemple, sur ces expressions régulières?
Gnoupi
+1. Cette réponse est très utile maintenant (après la modification) - je ne savais pas que vous pouviez faire une telle manipulation de chaîne dans Bash.
Jonik
En effet, beaucoup mieux maintenant, avec des exemples. +1
Gnoupi
0

En voici une autre:

find -name "*.jpg" -printf '"%p" "%h/%TY%Tm%Td %TH%TM %f"\n' | while read -r f
do
    eval "mv ${f}"
done
En pause jusqu'à nouvel ordre.
la source
0

Il y a toujours plus d'une façon de le faire. J'ai mis le script suivant sous / usr / local / bin / mrename.

Ensuite, dans le script contenant les fichiers photo, tapez simplement: mrename

Il y a aussi une fonctionnalité optionnelle commentée dans le script pour mettre à l'échelle les photos (en utilisant ImageMagick).

J'espère que cela est utile pour certaines personnes.

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

la source
0

Vous pouvez utiliser l' -X/--keep-extensionoption avec rename(version 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 pour Mac depuis Homebrew et pour Linux depuis Linuxbrew (entre autres options d'installation bien sûr).

John
la source