web-dev-qa-db-ger.com

Umbenennen sequentieller Dateien im Stapel durch Auffüllen mit Nullen

Ich habe eine Reihe von Dateien, die so heißen:

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

Was ist der einfachste Weg, diese umzubenennen, um einer Konvention zu entsprechen, z. mit maximal vier Dezimalstellen, damit die Dateien benannt werden:

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

Dies sollte in Unix/Linux/BSD einfach sein, obwohl ich auch Zugriff auf Windows habe. Jede Sprache ist in Ordnung, aber ich interessiere mich für einige wirklich nette Einzeiler (wenn es welche gibt?).

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))

sie können eine Liste der gültigen Dateinamen erstellen, vorausgesetzt, dass alle Dateien, die mit "output_" beginnen und mit ".png" enden, gültige Dateien sind:

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

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

Mit anderen Worten, ich ersetze file1.png durch file001.png und file20.png durch file020.png und so weiter. So geht's in bash

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

Speichern Sie das Obige in einer Datei mit dem Namen zeropad.sh und führen Sie dann den folgenden Befehl aus, um es ausführbar zu machen

chmod +x ./zeropad.sh

Sie können das zeropad.sh-Skript dann wie folgt verwenden

./zeropad.sh frame1.png

das wird das Ergebnis zurückgeben

frame001.png

Alles, was bleibt, ist, dieses Skript zu verwenden, um alle .png-Dateien im aktuellen Verzeichnis umzubenennen, so dass sie nicht hinzugefügt werden.

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

Perl

(von: Nullpunkt umbenennen, z. B. 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);

Umbenennen

Auch von oben antworten:

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

Ziemlich einfach, obwohl es einige Funktionen kombiniert, die nicht sofort offensichtlich sind:

@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: Falsch gelesen, dass Sie nicht nach einer Batch-Datei suchen, sondern nach einer Lösung in einer beliebigen Sprache. Das tut mir leid. Dafür entschädigen Sie einen PowerShell-Einzeiler:

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

Stecken Sie einen ?{$_.basename-match'_\d+'} dort ein, wenn Sie andere Dateien haben, die diesem Muster nicht folgen.

13
Joey

Ich musste das eigentlich nur unter OSX machen. Hier sind die Skripte, die ich dafür erstellt habe - einzeilig!

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

Here ist ein Python-Skript, das ich geschrieben habe, das abhängig von der größten vorhandenen Zahl Nullen auffüllt und nicht nummerierte Dateien im angegebenen Verzeichnis ignoriert. Verwendungszweck:

python ensure_zero_padding_in_numbering_of_files.py /path/to/directory

Hauptteil des Skripts:

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

Für die Massenumbenennung ist die einzige safe -Lösung mmv— die Überprüfung auf Kollisionen und die Umbenennung in Ketten und Zyklen, was über die meisten Skripts hinausgeht. Leider ist das Auffüllen mit Nullen nicht zu heiß. Ein Geschmack:

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

Hier ist eine Problemumgehung:

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

Das ist es!

Ich verfolge Adams Lösung für OSX.

Einige Gotchyas, denen ich in meinem Szenario begegnet bin, waren:

  1. Ich hatte eine Reihe von .mp3-Dateien, so dass der sed das ' 3 ' im Suffix ' .mp3 ' einfing. (Ich habe basename anstelle von echo verwendet, um dies zu korrigieren)
  2. Meine .mp3-Dateien enthielten Leerzeichen in ihren Namen, z. B. " audio track 1.mp3 ". Dies führte dazu, dass basename + sed etwas schief ging, sodass ich den Parameter "$ i" angeben musste.

Am Ende sah meine Conversion-Linie so aus:

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