web-dev-qa-db-fra.com

Batch renommer des fichiers séquentiels en remplissant avec des zéros

J'ai un tas de fichiers nommés comme suit:

output_1.png
output_2.png
...
output_10.png
...
output_120.png

Quel est le moyen le plus simple de renommer ceux qui correspondent à une convention, par exemple avec un maximum de quatre décimales pour que les fichiers soient nommés:

output_0001.png
output_0002.png
...
output_0010.png
output_0120.png

Cela devrait être facile sous Unix/Linux/BSD, même si j'ai également accès à Windows. Toutes les langues sont acceptables, mais je suis intéressé par des one-liners vraiment bien (s'il y en a?).

28
slhck

Python

import os
path = '/path/to/files/'
for filename in os.listdir(path):
    prefix, num = filename[:-4].split('_')
    num = num.zfill(4)
    new_filename = prefix + "_" + num + ".png"
    os.rename(os.path.join(path, filename), os.path.join(path, new_filename))

vous pouvez compiler une liste de noms de fichiers valides en supposant que tous les fichiers commençant par "output_" et finissant par ".png" sont des fichiers valides:

l = [(x, "output" + x[7:-4].zfill(4) + ".png") for x in os.listdir(path) if x.startswith("output_") and x.endswith(".png")]

for oldname, newname in l:
    os.rename(os.path.join(path,oldname), os.path.join(path,newname))

Bash

(de: http://www.walkingrandomly.com/?p=2850 )

En d'autres termes, je remplace fichier1.png par fichier001.png et fichier20.png par fichier020.png, etc. Voici comment faire cela en bash

#!/bin/bash
num=`expr match "$1" '[^0-9]*\([0-9]\+\).*'`
paddednum=`printf "%03d" $num`
echo ${1/$num/$paddednum}

Enregistrez ce qui précède dans un fichier appelé zeropad.sh, puis exécutez la commande suivante pour le rendre exécutable.

chmod +x ./zeropad.sh

Vous pouvez ensuite utiliser le script zeropad.sh comme suit

./zeropad.sh frame1.png

qui retournera le résultat

frame001.png

Il ne reste plus qu'à utiliser ce script pour renommer tous les fichiers .png du répertoire en cours de manière à ce qu'ils soient zéros ajoutés.

for i in *.png;do mv $i `./zeropad.sh $i`; done

Perl

(from: Renommer le pavé zéro, par exemple Image (2) .jpg -> Image (002) .jpg )

use strict;
use warnings;
use File::Find;

sub pad_left {
   my $num = shift;

   if ($num < 10) {
      $num = "00$num";
   }
   elsif ($num < 100) {
      $num = "0$num";
   }

   return $num;
}

sub new_name {
   if (/\.jpg$/) {
      my $name = $File::Find::name;
      my $new_name;
      ($new_name = $name) =~ s/^(.+\/[\w ]+\()(\d+)\)/$1 . &pad_left($2) .')'/e;
      rename($name, $new_name);
      print "$name --> $new_name\n";
   }
}

chomp(my $localdir = `pwd`);# invoke the script in the parent-directory of the
                            # image-containing sub-directories

find(\&new_name, $localdir);

Renommer

Aussi de la réponse ci-dessus:

rename 's/\d+/sprintf("%04d",$&)/e' *.png
39
DTing

Assez facile, bien qu'il combine quelques fonctionnalités qui ne sont pas immédiatement évidentes:

@echo off
setlocal enableextensions enabledelayedexpansion
rem iterate over all PNG files:
for %%f in (*.png) do (
    rem store file name without extension
    set FileName=%%~nf
    rem strip the "output_"
    set FileName=!FileName:output_=!
    rem Add leading zeroes:
    set FileName=000!FileName!
    rem Trim to only four digits, from the end
    set FileName=!FileName:~-4!
    rem Add "output_" and extension again
    set FileName=output_!FileName!%%~xf
    rem Rename the file
    rename "%%f" "!FileName!"
)

Edit: indiquez que vous ne recherchez pas un fichier de commandes, mais une solution dans n'importe quelle langue. Désolé. Pour compenser cela, un PowerShell one-liner:

gci *.png|%{rni $_ ('output_{0:0000}.png' -f +($_.basename-split'_')[1])}

Collez un ?{$_.basename-match'_\d+'} à cet endroit si d'autres fichiers ne suivent pas ce modèle.

13
Joey

En fait, je devais juste le faire sous OSX. Voici les scripts que j'ai créés pour cela - une seule ligne!

> for i in output_*.png;do mv $i `printf output_%04d.png $(echo $i | sed 's/[^0-9]*//g')`; done
4
Adam

Here est un script Python que j'ai écrit et qui compile les zéros en fonction du plus grand nombre présent et ignore les fichiers non numérotés du répertoire donné. Usage:

python ensure_zero_padding_in_numbering_of_files.py /path/to/directory

Corps du script:

import argparse
import os
import re
import sys

def main(cmdline):

    parser = argparse.ArgumentParser(
        description='Ensure zero padding in numbering of files.')
    parser.add_argument('path', type=str,
        help='path to the directory containing the files')
    args = parser.parse_args()
    path = args.path

    numbered = re.compile(r'(.*?)(\d+)\.(.*)')

    numbered_fnames = [fname for fname in os.listdir(path)
                       if numbered.search(fname)]

    max_digits = max(len(numbered.search(fname).group(2))
                     for fname in numbered_fnames)

    for fname in numbered_fnames:
        _, prefix, num, ext, _  = numbered.split(fname, maxsplit=1)
        num = num.zfill(max_digits)
        new_fname = "{}{}.{}".format(prefix, num, ext)
        if fname != new_fname:
            os.rename(os.path.join(path, fname), os.path.join(path, new_fname))
            print "Renamed {} to {}".format(fname, new_fname)
        else:
            print "{} seems fine".format(fname)

if __== "__main__":
    sys.exit(main(sys.argv[1:]))
2
Donny Winston

Pour renommer en masse le seul safe solution est mmv -, il vérifie les collisions et permet de renommer des chaînes et des cycles, ce qui dépasse la plupart des scripts. Malheureusement, zéro padding n'est pas trop chaud. Une saveur:

c:> mmv output_[0-9].png output_000#1.png

Voici une solution de contournement:

c:> type file
mmv
[^0-9][0-9] #1\00#2
[^0-9][0-9][^0-9] #1\00#2#3
[^0-9][0-9][0-9] #1\0#2#3
[^0-9][0-9][0-9][^0-9] #1\0#2#3
c:> mmv <file
2
bobbogo
$rename output_ output_0 output_?   # adding 1 zero to names ended in 1 digit
$rename output_ output_0 output_??  # adding 1 zero to names ended in 2 digits
$rename output_ output_0 output_??? # adding 1 zero to names ended in 3 digits

C'est tout!

Je suis la solution d'Adam pour OSX.

Voici quelques gotchyas rencontrés dans mon scénario:

  1. J'avais un ensemble de fichiers .mp3, donc le sed capturait le suffixe ' 3 ' dans le suffixe ' .mp3 '. (J'ai utilisé basename au lieu de echo pour rectifier cela)
  2. Les noms de mes fichiers .mp3, par exemple, " piste audio 1.mp3 ", étaient à l'origine de la confusion de Basename + sed. J'ai donc dû citer le paramètre "$ i".

Au final, ma ligne de conversion ressemblait à ceci:

for i in *.mp3 ; do mv "$i" `printf "track_%02d.mp3\n" $(basename "$i" .mp3 | sed 's/[^0-9]*//g')` ; done
0
Gurce