ubuntuusers.de

Bash: Files umbenennen => "richtige" Reihenfolge

Status: Gelöst | Ubuntu-Version: Nicht spezifiziert
Antworten |

DaWi

Anmeldungsdatum:
19. Februar 2008

Beiträge: 132

Hallo Gemeinde,

Ich habe mal eine Frage:

wenn ich 2 Files habe:

file-1.txt
file-10.txt

sind die ,wenn ich ls | sort (bzw. find, locate, was auch immer) mache, ja in der "falschen" Reihenfolge, da 10>1. (Also die sind natürlich in der richtigen Reihenfolge, rein lexikalisch....)

Eine Lösung wäre jetzt ja die files umzubennen, also
file-001.txt
file-010.txt
was das Probleme lösen würde. Leider weiß ich nicht wie ich sowas anstellen kann. Ich habe schon rumgesucht, finde aber leider nix.
EDIT: bzw. verstehe es nicht
Hat jemand eine Idee wie ich das machen könnte? Oder einen besseren Lösungsvorschlag?

Grüße DaWi

deifl

Avatar von deifl

Anmeldungsdatum:
18. August 2006

Beiträge: 132

Wohnort: Esslingen

Wenn die Dateinamen alle mit den gleichen Zeichen vor der Zahl beginnen, also file-1.ext, file-23.ext, file-42.ext, file-20ext, file -100.ext, usw., dann koenntest du mit der zsh folgendes versuchen:

autoload zmv
zmv 'file-(*).ext' 'file-${(l:4::0:)1}.ext'


Weitere super Beispiele finden sich bei den zsh-lovers: http://grml.org/zsh/zsh-lovers.html

Lutki

Avatar von Lutki

Anmeldungsdatum:
17. Juni 2006

Beiträge: 372

Na ja, mal eine kleine Anregung - das Skript erst ausführen, wenn du es verstanden hast.

#!/bin/bash
dir=`pwd`
i=0
for f in `find $dir -name "*.txt" 2>/dev/null`; do
    (( i++ ));
    newfile="new-file-`printf %05.f $i`.txt"
    if [ ! -f "$dir/$newfile" ]; then
        mv "$f" "$dir/$newfile"
    fi
done

MFG

DaWi

(Themenstarter)

Anmeldungsdatum:
19. Februar 2008

Beiträge: 132

    (( i++ ));
    newfile="new-file-`printf %05.f $i`.txt"

Mmmmhh, entweder ich versthe das nicht, oder das haut nicht hin.

ein beispiel.

file-10.txt.
file-1.txt
(falsche Reihenfolge!, so kommen die ja auch)

Also deine Schleife macht dann das.
beim ersten i=0.
Er printet also 00000 → newfile-00000.txt
beim zweiten i=1
Er printet also 00001 → newfile-000001.txt

Also:
file-10.txt → newfile-00000.txt
file-1.txt → newfile-000001.txt

Das ist doch wieder in der falschen Reihenfolge, oder nicht?

Grüße DaWi

ps: Aber printf %0.5.f $i is was ich suche. Ich müsste nun noch diese Zahl aus den files kriegen.

was so geht.

(habs hinbekommen)

bla='file-14.txt'

bla2=${bla%.* }

bla3=${bla2:5}

printf %05.f $bla3

danke für den hinweis mit dem printf

DaWi

(Themenstarter)

Anmeldungsdatum:
19. Februar 2008

Beiträge: 132

habe es jetzt noch ein wenig hübsch gemacht.

4 Parameter.

1.) Die Weite. also bei file-4235 siond 5, f i l e und -.
2.) Das format
3.) den ausgabe namen, also newfile oder so etwas (wonach dann die neuen nummer kommen)
4.) den eingabe namen (Teilstring), in meinem beispiel file

Ich bedanke mich bei allen. Wieder was dazu gelernt

Grüße DaWi

#!/bin/bash
dir=`pwd`

if [ $# -lt "4" ]
then 
echo "Zu wenig infos"
echo "name_skript <Weite> <Format> <Ausgabename> <eingabe_teilstring>"
exit 1
fi


for f in $(find $4* 2>/dev/null)
do

buf1=${f%.*}
buf2=${buf1:$1}

    newfile="$3`printf %05.f $buf2`.$2"
  


 if [ ! -f "$dir/$2" ]; then
       cp "$f" "$dir/$newfile"
 fi

done  

Lux Team-Icon

Avatar von Lux

Anmeldungsdatum:
10. November 2005

Beiträge: 5152

Wohnort: Grüt (Gossau ZH), Schweiz

Hi,

vorher Backup machen und versuche dann einmal

rename 's/file-(\d{1})\.txt/file-0$1.txt/' *

.

Damit ersetzt Du in Deinen Dateien alles, wo genau eine Ziffer vorkommt durch 0 und die Ziffer. Wenn Du in die geschweiften Klammern eine 2 schreibst, ersetzt Du alle zweiziffrigen Zahlen durch 0 und die Zahl.

Dirk

Lutki

Avatar von Lutki

Anmeldungsdatum:
17. Juni 2006

Beiträge: 372

DaWi hat geschrieben:

Also deine Schleife macht dann das.
beim ersten i=0.
Er printet also 00000 → newfile-00000.txt
beim zweiten i=1
Er printet also 00001 → newfile-000001.txt

Also:
file-10.txt → newfile-00000.txt
file-1.txt → newfile-000001.txt

Das ist doch wieder in der falschen Reihenfolge, oder nicht?

Beim ersten $i ist es schon 1; also newfile-00001.txt
Der Witz war: es werden alle txt-Dateien geändert, falls es noch keine newfile-XXXXX.txt gibt. ☺

Bei find fehlt bei Dir aber noch das $dir?!

MFG

DaWi

(Themenstarter)

Anmeldungsdatum:
19. Februar 2008

Beiträge: 132

rename 's/file-(\d{1})\.txt/file-0$1.txt/' *

Klasse, das klappt auch, da alle einerstellen bearbeitet werden genügt mir dieses Lösung auch.

Lutki hat geschrieben:

Beim ersten $i ist es schon 1; also newfile-00001.txt
Der Witz war: es werden alle txt-Dateien geändert, falls es noch keine newfile-XXXXX.txt gibt. ☺

Bei find fehlt bei Dir aber noch das $dir?!

Also klar, man fängt mit 1 an, ändert aber nichts an der Reihenfolge.

Aber du hattes also so eine ähnliche Idee wie Lux. Wenn man dann nämlich printf %02.f $i nimmt, werden nur die einerstellen geändert. So gehts dann auch.
(also beim find fehlt das $dir nicht. man könnte es hinschreiben, ist aber unnötig. Da du so nur $(pwd) hinschreibst passiert nichts)

Beide Lösungen haben aber den nachteil, dass sich sich nur für feste stellenanzahlen eigenen. Also wenn man das Problem 5 stufig hätte: 00001 bis 34546, so müsste man beide sachen 4 mal aufrufen (lassen).

Grüße DaWi

EDIT: Also man könnte es auch so machen:

for i in {1..5}
do
rename 's/file-(\d{$i})\.txt/file-0$1.txt/' *
done

Lux Team-Icon

Avatar von Lux

Anmeldungsdatum:
10. November 2005

Beiträge: 5152

Wohnort: Grüt (Gossau ZH), Schweiz

DaWi hat geschrieben:

for i in {1..5}
do
rename 's/file-(\d{$i})\.txt/file-0$1.txt/' *
done

Das geht nicht, da Variablen nicht innerhalb von einfachen Anführungszeichen substituiert werden.

Gruss

Dirk

Lutki

Avatar von Lutki

Anmeldungsdatum:
17. Juni 2006

Beiträge: 372

DaWi hat geschrieben:

Beide Lösungen haben aber den nachteil, dass sich sich nur für feste stellenanzahlen eigenen. Also wenn man das Problem 5 stufig hätte: 00001 bis 34546, so müsste man beide sachen 4 mal aufrufen (lassen).

EDIT: Also man könnte es auch so machen:

for i in {1..5}
do
rename 's/file-(\d{$i})\.txt/file-0$1.txt/' *
done

Das wird so nicht funktionieren. Wenn es funktionieren würde,
hättest du aber nicht das Ergebnis, dass du haben willst.

Da rename eh nur ein Perlskript ist, könntest du dir auch gleich etwas in perl bauen, so etwa:

#!/usr/bin/perl -w
use strict;
if (!@ARGV) {
    print "Error: no args!\n";
    print "Usage: $0 /tmp/*.txt\n";
    exit 1;
}
for (@ARGV) {
    if (my ($a, $d, $z) = /^([^0-9]+)(\d+)(\S+)/) {
        my $n = sprintf ("%0.5d", $d);
        if (! -e "$a$n$z") {
            rename $_, "$a$n$z" || warn "Warn: $!\n";
        }
    }
}
# eof

Viele Wege führen nach Rom! ☺

MFG

JFG

Avatar von JFG

Anmeldungsdatum:
17. September 2007

Beiträge: Zähle...

Ich würde wahrscheinlich auch in der Kommandozeile rename verwenden, je nachdem, welcher Gestalt die Dateien sind..

$ rename 's/-/-0/' file-?.txt

Zum Beispiel ☺

Will ich dann doch noch eine Null bei allen dazu, führe ich es eben nochmal aus (Strg+p, Strg+w, file-*, Enter – oder: Strg+p, Alt+b, Strg+b, ?, Enter).

Sowas braucht man ja nicht allzu allgemein zu halten, da es meist eh nur einmal gebraucht wird.. und ich glaube, ich wäre so recht schnell fertig ☺

Antworten |