ubuntuusers.de

bash-script:Dateinname abschneiden(Endung muss erhalten bleiben) und umbennen/Problem

Status: Gelöst | Ubuntu-Version: Ubuntu 12.04 (Precise Pangolin)
Antworten |

ITNew85

Anmeldungsdatum:
21. November 2014

Beiträge: 5

Servus zusammen,

Ich bin ein ziemlicher Neuling in Sachen Bash&Co.

Ich habe ein kleines Problem, welches ich kurz beschreiben möchte. Ich besitze ca 1500 Dateien die sich in der Länge des Dateinamens nur um 2 Stellen unterscheiden.

Beispiel:

59k_1bin_hemocyanin_pos_9_1-2_1.mrc; 
59k_1bin_hemocyanin_pos_99_3-3_1.mrc; 
59k_1bin_hemocyanin_pos_157_3-1_1.mrc

Heißt die letzte Datei ist 2 Zeichen länger als die erste.

Diese Dateien muss ich nun umbenennen und zwar einfach auflisten von 1-1500 also

59k_1bin_hemocyanin_pos_9_1-2_1.mrc --> 1.mrc ; 
59k_1bin_hemocyanin_pos_9_1-2_2.mrc --> 2.mrc
usw..

Nun zu meinem Script was ohne Probleme klappt wenn die Dateien alle gleich lang sind

1
2
3
4
5
6
7

COUNTER=0

for i in `ls *.mrc | cut -b 1-33`; do
        mv ${i}.mrc ${COUNTER}.mrc
        let COUNTER=COUNTER+1
done

wenn ich

cut -b 1-33

nehme, sagt er bei den kürzeren Dateien, dass er diese nicht findet... wenn er an eine Datei mit der richtigen Länge ankommt benennt er sie um, fängt aber dann nicht mehr mit 1 an sondern an der Stelle wo er gerade ist also zum Beispiel 32.mrc 33.mrc 34.mrc dann kommen wieder Dateien die von der Länger nicht passen, bis wieder eine passende kommt. Dann gehts weiter mit zB. 84.mrc 85.mrc...

Meine Frage nun, gibt es eine Möglichkeit beim cut-Befehl etwas zu verwenden das einfach nur den Dateinnamen abschneidet, die Endung behält und dann von 1-1500 umbenennt? Das Abschneiden von 1 oder 2 Zeichen bei den längeren Dateien ging bei mir in die Hose da plötzlich doppelte Dateien auftauchten ☹

Ich hoffe ich konnte mein Problem einigermaßen beschreiben. Mir fällt einfach gerad überhaupt nichts ein

Liebe Grüße und Danke schon mal

Bearbeitet von rklm:

Codeblöcke für die Lesbarkeit. Bitte die Vorschaufunktion nutzen.

Krümelomat

Avatar von Krümelomat

Anmeldungsdatum:
18. Oktober 2010

Beiträge: 1115

Ja, der Computer listet anders als wir Menschen zählen. Ich würde dir ganz einfach Irvan View empfehlen, vielleicht kann das auch XNview? Auf jeden Fall läuft Irvan View unter wine und listet die Dateien wie im Dateimanager auf. Datei-Batch-Konvertieren-Umbenennen. Dann auf sortieren klicken, dei Muster gibst du ### ein, dann bennent er sie so: 001.* 002.* ... Dann gehst du dem Problem der Auflistung in der Bash in Zukunft aus dem Weg. Getestete Version Iv 4.30.

Vielleicht helfen dir aber auch meine Bash Experimente:

Dateien 1.txt bis 12.txt werden in Array fl eingelesen in Array srt sortiert die Felder mit cnt gezählt. Die Forschleife soll ein=Dateiname und aus=neuerDateiname generieren und in Befehl do..... verarbeiten zu 0001.txt.....

fl=( *.* )
cnt=${#fl[@]}
echo $cnt
srt=( $(printf "%s\n" ${fl[@]} | sort -g) )
echo ${srt[@]}
# for (( i=0 ; i < ${#fl[@]} ; ++i ))
#for i in "${!fl[@]}"
for (( i = 0 ; i < cnt ; ++i ))
do
printf -v ein '%s' "${srt[i]%.*}"
printf -v aus '%03d' "$ein"
echo "${ein}.* zu ${aus}.jpg"
done


----

fl=( *.txt )
srt=( $(printf "%s\n" ${fl[@]} | sort -g) )
for i in "${!fl[@]}"
do
printf -v ein '%s' "${srt[i]%.*}"
printf -v aus '%03d' "$ein"
mv ${ein}.* ${aus}.jpg
done

---------------------------------------------------------

Dateien in Array, daraus Sortiertes, daraus Verändertes, beides parallel in Datei schreiben. Zum Umbenennen Konvertieren Anpassen

p=("*.*")
unset u; u=( $(printf "%s\n" "${p[@]%.*}" | sort -h))
echo ${u[@]}
s=( $(printf "%s\n" ${p[@]} | sort -g))
echo ${s[@]}
read -r -d'' -a t < <(cat zz.txt)

-->Ausführen:
while read line; do $line; done < zz.txt

-->In Array pressen:
i=0; while read -r line; do t[i++]="$line"; done < zz.txt
echo ${t[@]}

while read -r line do; t+=( "$line" ); done < zz.txt
echo ${t[@]}

while read -r; do t+=( "$REPLY" ); done < zz.txt

for ((i=0; i<${#u[*]}; i++)); do echo echo ${s[i]} zu ${u[i]}; done >zz.txt
echo ${t[@]}

IFS=$'\n'
t=($(cat zz.txt)) # t
echo ${t[@]}

read -r -d'\n' -a t < <(cat zz.txt)
echo ${t[@]}

mapfile -t t < zz.txt
echo ${t[@]}

-->Ausgeben:
printf "%s\n" "$(<zz.txt)"

--------------------------------------------------
rename.ul : Bash Reihenfolge umbenennen

orginal		bash abarbeitet	richtig:
1.dat		3					001.dat
2.dat		4					002.dat
9.dat		5					003.dat
10.dat		1					004.dat
11.dat		2					005.dat

rename.ul  "" 00   ?.*
rename.ul  ""  0  ??.*


'''rename.ul'''

*=Wildcard *name oder name*name usw.
?=jeweis 1 Zeichen ???name oder name?????name

rename.ul "search" "replace" infilepattern
rename.ul "zu suchender Ausdruck" "zu ersetzender Ausdruck" *zu suchender Ausdruck*
rename.ul "" "p0" *.txt (a.txt wird zu p0a.txt ...)
rename.ul "p0" "" *p0* (p0a.txt wird zu a.txt)

1.dat bis 20.dat in 001.dat bis 020.dat:
rename.ul  "" 00   ?.*
rename.ul  ""  0  ??.*

seahawk1986

Anmeldungsdatum:
27. Oktober 2006

Beiträge: 11243

Wohnort: München

An die Endung der Datei in der Variablen filename kommt man z.B. so:

1
extension="${filename##*.}"

Aber eigentlich genügt doch so etwas:

1
2
3
4
5
6
a=0
for i in *.mrc; do
  printf -v new "%04d.mrc" ${a} #04 pad to length of 4
  mv -- "$i" "$new"
  let a=a+1
done

ITNew85

(Themenstarter)

Anmeldungsdatum:
21. November 2014

Beiträge: 5

@Seahawk: Das Script läuft wie geschmiert... Vielen lieben Dank.

Könntest du mir kurz erklären warum du das erste Skript was du gepostet hast überarbeitet hast?

seahawk1986

Anmeldungsdatum:
27. Oktober 2006

Beiträge: 11243

Wohnort: München

ITNew85 schrieb:

Könntest du mir kurz erklären warum du das erste Skript was du gepostet hast überarbeitet hast?

Weil man printf auch direkt in eine Variable schreiben lassen kann ☺

1
printf -v new "%04d.mrc" ${a} #04 pad to length of 4

finde ich schöner als

1
new=$(printf "%04d.mrc" "$a") #04 pad to length of 4

rklm Team-Icon

Projektleitung

Anmeldungsdatum:
16. Oktober 2011

Beiträge: 13166

ITNew85 schrieb:

Könntest du mir kurz erklären warum du das erste Skript was du gepostet hast überarbeitet hast?

Vermutlich, weil es nicht das getan hat, was Du erreichen möchtest ☺, und weil ls ein denkbar schlechtes Werkzeug ist um Dateilisten zu erzeugen. Letzeres hatte ich neulich schon mal andernorts dargelegt.

ITNew85

(Themenstarter)

Anmeldungsdatum:
21. November 2014

Beiträge: 5

Vielen lieben Dank an alle

wxpte

Anmeldungsdatum:
20. Januar 2007

Beiträge: 1388

Da der Fall bereits gelöst ist, nur noch eine Ergänzung und eine Frage:

ITNew85 schrieb:

Meine Frage nun, gibt es eine Möglichkeit beim cut-Befehl etwas zu verwenden das einfach nur den Dateinnamen abschneidet, die Endung behält

Auch mit dem cut-Befehl gibt es natürlich eine Möglichkeit, setzt aber voraus, dass im Hauptnamen kein zweiter Punkt auftaucht:

cut -f2 -d\.

Ansonsten wird es etwas komplizierter, weil man das Skript erst dazu bringen muss, die Anzahl der im Dateinamen vorkommenden Punkte zu zählen.

seahawk1986 schrieb:

An die Endung der Datei in der Variablen filename kommt man z.B. so:

1
extension="${filename##*.}"

Ja? Ich habe das soeben ausprobiert, bekomme aber auch mit

echo $filename

den vollen Dateinamen angezeigt (also Hauptnamen und Extension).

seahawk1986

Anmeldungsdatum:
27. Oktober 2006

Beiträge: 11243

Wohnort: München

WinXP to Edgy schrieb:

seahawk1986 schrieb:

An die Endung der Datei in der Variablen filename kommt man z.B. so:

1
extension="${filename##*.}"

Ja? Ich habe das soeben ausprobiert, bekomme aber auch mit

echo $filename

den vollen Dateinamen angezeigt (also Hauptnamen und Extension).

Kleines Beispiel:

1
2
3
filename="myFile.txt"
extension="${filename##*.}"
echo $extension

wxpte

Anmeldungsdatum:
20. Januar 2007

Beiträge: 1388

Komisch, da geht's. Aber hier:

1
2
3
4
5
6
filename="Madoka*"
echo $filename
Madoka_Rebellion_Transkript.odt
extension="${filename##*.}"
echo $extension
Madoka_Rebellion_Transkript.odt

haut das aus irgend einem Grunde nicht hin.

track

Avatar von track

Anmeldungsdatum:
26. Juni 2008

Beiträge: 7174

Wohnort: Wolfen (S-A)

WinXP to Edgy schrieb:

1
2
3
4
5
6
filename="Madoka*"
echo $filename
Madoka_Rebellion_Transkript.odt
extension="${filename##*.}"
echo $extension
Madoka_Rebellion_Transkript.odt

haut das aus irgend einem Grunde nicht hin.

Hihi ... schau Dir mal an, was genau in der Variablen drin steht:

echo "$extension"

und dann bedenke: zuerst wird die Variable expandiert, und danach, ganz am Ende der Dateiname ... 😉
(in der Variablen gab es ja noch gar keinen Punkt, sondern nur den Stern !)

LG,

track

wxpte

Anmeldungsdatum:
20. Januar 2007

Beiträge: 1388

Oha, also das ist der Grund. Die Auflösung der Wildcards ist ja noch tückischer, als ich dachte. Dann geht es letzten Endes doch nicht ohne die "Krücke" echo:

filename="$(echo Madoka*)"

Danke für die Info. 👍

rklm Team-Icon

Projektleitung

Anmeldungsdatum:
16. Oktober 2011

Beiträge: 13166

WinXP to Edgy schrieb:

Oha, also das ist der Grund. Die Auflösung der Wildcards ist ja noch tückischer, als ich dachte. Dann geht es letzten Endes doch nicht ohne die "Krücke" echo:

filename="$(echo Madoka*)"

Da Du ja sowieso mehrere verarbeiten willst, bietet sich auch

1
2
3
for filename in Madoka*; do
  echo "$filename"
done

an.

wxpte

Anmeldungsdatum:
20. Januar 2007

Beiträge: 1388

rklm schrieb:

Da Du ja sowieso mehrere verarbeiten willst, ...

Nein, in diesem Fall wollte ich einfach nur den Codeschnippsel nachvollziehen, den seahawk1986 vorgeschlagen hat. Ansonsten hast du natürlich recht: für die Verarbeitung mehrerer Dateien mit Jokerzeichen gibt es nichts besseres, als eine for-Schleife. ☺

Antworten |