Diese Website existiert nur weil wir Werbung mit AdSense ausliefern.
Bitte den AdBlocker daher auf dieser Website ausschalten! Danke.

[gelöst] bash-Script mit Doppelschleife

Alles rund um die verschiedenen Konsolen und shells sowie die Programmierung unter Linux

Moderator: Moderatoren

Christina
Member
Member
Beiträge: 102
Registriert: 4. Mär 2019, 13:44

[gelöst] bash-Script mit Doppelschleife

Beitrag von Christina »

Hallo,

ich möchte ganz alte DAT-Band-Überspielungen (von meinem Papa analog über die Soundkarte gemacht) durch neue digitale Überspielungen (mit Solid State Recorder auf SD-Card) ersetzen.
Jetzt möchte ich aber nicht jede Flac-Datei von Hand neu mit ID3-Tags beschriften, sondern die Tags der alten Flac-Dateien übernehmen.

Verzeichnis alte Aufnahme z.B.:

Code: Alles auswählen

cd Musik-Alben/Dolly\ Parton/Here\ You\ Come\ Again/
ls -1
01. Here You Come Again.flac
02. Baby Come Out Tonight.flac
03. It’s All Wrong, but It’s All Right.flac
04. Me and Little Andy.flac
05. Lovin’ You.flac
06. Cowgirl and the Dandy.flac
07. Two Doors Down.flac
08. God’s Coloring Book.flac
09. As Soon as I Touched Him.flac
10. Sweet Music Man.flac
Verzeichnis neue Aufnahme:

Code: Alles auswählen

ls -1 /home/christina/Tascam/Dolly\ Parton/
T063_DAT-Band.flac
T064_DAT-Band.flac
T065_DAT-Band.flac
T066_DAT-Band.flac
T067_DAT-Band.flac
T068_DAT-Band.flac
T069_DAT-Band.flac
T070_DAT-Band.flac
T071_DAT-Band.flac
T072_DAT-Band.flac
1. Kommando (im alte-Aufnahme-Verzeichnis):

Code: Alles auswählen

metaflac --export-tags-to=- 01.\ Here\ You\ Come\ Again.flac \
| metaflac --remove-all-tags --import-tags-from=- /home/christina/Tascam/Dolly\ Parton/T063_DAT-Band.flac
--export-tags-to={stdout} | --import-tags-from={stdin}

Jetzt fehlt mir nur ein bash-Script, das das automatisch für alle Dateien in den beiden getrennten Verzeichnissen übernimmt. Die neu getaggten "Txxx_DAT-Band.flac"-Dateien kann ich später für jedes Verzeichnis einfach mit Kid3-qt alle auf einmal umbenennen. (Filename: Format: %{track}. %{title})

Vom Prinzip mit einer Schleife, die alle Dateinamen in einem Verzeichnis einliest, wäre das ja so wie in diesem Thema:
bash-Script, um viele Dateien automatisch zu verlinken
Jetzt brauche ich aber zwei verschachtelte Schleifen, die jeweils ein Verzeichnis einlesen und die Dateinamen immer paarweise als Argument an die beiden metaflac-Befehle übergeben.
Knifflig, die bash.
Könnt ihr mir hier vielleicht weiterhelfen, bitte?
lg
Christina
Zuletzt geändert von Christina am 20. Sep 2020, 17:13, insgesamt 1-mal geändert.
Gräfin Klara
Hacker
Hacker
Beiträge: 623
Registriert: 23. Jun 2008, 20:51

Re: bash-Script mit Doppelschleife

Beitrag von Gräfin Klara »

Christina hat geschrieben: 19. Sep 2020, 12:49 Hallo,

Knifflig, die bash.
Könnt ihr mir hier vielleicht weiterhelfen, bitte?
lg
Christina
Ich denke, du solltest alle files beider directories in je ein array lesen
Christina
Member
Member
Beiträge: 102
Registriert: 4. Mär 2019, 13:44

Re: bash-Script mit Doppelschleife

Beitrag von Christina »

Gräfin Klara hat geschrieben: 19. Sep 2020, 20:15 Ich denke, du solltest alle files beider directories in je ein array lesen
Ich weiß leider nicht, wie das in der bash geht. Diese Lösung würde mich schon interessieren, wenn der Programmieraufwand nicht zu groß ist.
In dem letzten Link-Script liegt das "Array" in {stdout}: "ls -1 *.$suffix | while read i"

:-) Ich kann mir aber auch mit einer Schleife einzelne temp-Dateien aus den Metadaten exakt nach dem Schema aus dem letzten Link-Script erstellen lassen und mit einer zweiten Schleife die Ziel-Flac-Dateien mit den temp-Dateien taggen.

Code: Alles auswählen

#!/bin/bash

echo -e "FLAC-Zielverzeichnis: \c"
read dirbasename
suffix="flac"

nr=1
ls -1 *.$suffix | while read i
do
    metaflac --export-tags-to="temp-$(printf "%02d" $nr)" "$i"
    echo "$i -> temp-$(printf "%02d" $nr)"
    let nr++
done
      
nr=1
ls -1 $dirbasename/*.$suffix | while read i
do   
    metaflac --remove-all-tags --import-tags-from="temp-$(printf "%02d" $nr)" "$i"
    echo "temp-$(printf "%02d" $nr) -> $i"
    let nr++
done

rm -f temp-??
Gräfin Klara
Hacker
Hacker
Beiträge: 623
Registriert: 23. Jun 2008, 20:51

Re: bash-Script mit Doppelschleife

Beitrag von Gräfin Klara »

Christina hat geschrieben: 20. Sep 2020, 11:28 :-) Ich kann mir aber auch mit einer Schleife einzelne temp-Dateien ...
Du kannst das lösen wie du willst
Christina hat geschrieben: 20. Sep 2020, 11:28 Ich weiß leider nicht, wie das in der bash geht. Diese Lösung würde mich schon interessieren, wenn der Programmieraufwand nicht zu groß ist.
Ist ganz einfach

Code: Alles auswählen

#!/bin/bash

fa=()   # filename array A
fb=()   # filename array B
i=0      # array index

# einlesen aller filenamen in 2 arrays
# wenn die filenamen auch den pfad halten sollen, dann schreibst du hier  -printf "%p/%f\n"
fa=($(find "/Musik-Alben/Dolly Parton/irgendwo" -maxdepth 1 -type f -name "*.flac" -printf "%f\n"))
fb=($(find "/home/christina/Dolly Parton blabla" -maxdepth 1 -type f -name "*.flac" -printf "%f\n"))

# erledigt

# nun lesen und ausgeben beider arrays mittels Indexierung
# in diese eine loop setzt du all dein metaflac Brimborium
for i in ${!fa[@]}; do
	printf "%.2d: %s = %s\n" "$i" "${fa[i]}" "${fb[i]}"
done
exit 0
Ausprobieren und Anpassen an deine Notwendigkeiten überlasse ich dir.
Max. 7 Zeilen code müssen reichen.

Gruß
Gräfin Klara
Christina
Member
Member
Beiträge: 102
Registriert: 4. Mär 2019, 13:44

Re: bash-Script mit Doppelschleife

Beitrag von Christina »

Hi Gräfin Klara,
das klappt so leider noch nicht.

1) Mit find bekomme ich als Ausgabe die Reihenfolge wie im Verzeichnis gespeichert, aber nicht alphanumerisch sortiert.

Code: Alles auswählen

echo $(find . -maxdepth 1 -type f -name "*.flac" -printf "%f\n")
01. Here You Come Again.flac 06. Cowgirl and the Dandy.flac 05. Lovin’ You.flac 08. God’s Coloring Book.flac 03. It’s All Wrong, but It’s All Right.flac 07. Two Doors Down.flac 09. As Soon as I Touched Him.flac 10. Sweet Music Man.flac 04. Me and Little Andy.flac 02. Baby Come Out Tonight.flac
Ich muss also ls verwenden.
2) Da die Dateinamen Leerstellen enthalten, bekomme ich bei den 10 Flac-Dateien 49 Strings im Array.
bash-Script:
(dirbasename=/home/christina/Tascam)

Code: Alles auswählen

#!/bin/bash

echo -e "FLAC-Zielverzeichnis: \c"
read dirbasename
suffix="flac"

fa=()   # filename array A
fb=()   # filename array B
i=0     # array index
fa=($(ls -1 *.$suffix))
fb=($(ls -1 $dirbasename/*.$suffix))
for i in ${!fa[@]}; do
        printf "%.2d: %s = %s\n" "$i" "${fa[i]}" "${fb[i]}"
done
exit 0
00: 01. = /home/christina/Tascam/01.
01: Here = Here
02: You = You
03: Come = Come
04: Again.flac = Again.flac
05: 02. = /home/christina/Tascam/02.
06: Baby = Baby
07: Come = Come
08: Out = Out
09: Tonight.flac = Tonight.flac
10: 03. = /home/christina/Tascam/03.
11: It’s = It’s
12: All = All
13: Wrong, = Wrong,
14: but = but
15: It’s = It’s
16: All = All
17: Right.flac = Right.flac

49: Man.flac = Man.flac
Gräfin Klara
Hacker
Hacker
Beiträge: 623
Registriert: 23. Jun 2008, 20:51

Re: bash-Script mit Doppelschleife

Beitrag von Gräfin Klara »

Christina hat geschrieben: 20. Sep 2020, 14:21 1) Mit find bekomme ich als Ausgabe die Reihenfolge wie im Verzeichnis gespeichert, aber nicht alphanumerisch sortiert.
Kein Problem

Code: Alles auswählen

find . -maxdepth 1 -type f -name "*.flac" -printf "%f\n" | sort -f
bzw.

Code: Alles auswählen

fa=($(find "/Musik-Alben/Dolly Parton/irgendwo" -maxdepth 1 -type f -name "*.flac" -printf "%f\n" | sort -f))
Dein 'echo' ist fehl am Platz


Christina hat geschrieben: 20. Sep 2020, 14:21 2) Da die Dateinamen Leerstellen enthalten, bekomme ich bei den 10 Flac-Dateien 49 Strings im Array.
Setze im script irgendwo am Beginn:

Code: Alles auswählen

IFS=$'\n'
Ausprobieren
abgdf
Guru
Guru
Beiträge: 3376
Registriert: 13. Apr 2004, 21:15

Re: bash-Script mit Doppelschleife

Beitrag von abgdf »

Christina hat geschrieben: 20. Sep 2020, 14:21Da die Dateinamen Leerstellen enthalten, bekomme ich bei den 10 Flac-Dateien 49 Strings im Array.
Ja, genau. Hatte ich Dir nicht deshalb schonmal gesagt, daß Leerstellen und Umlaute, bzw. Unicode-Zeichen in Dateinamen problematisch sind?
Christina hat geschrieben: 20. Sep 2020, 14:21Knifflig, die bash.
Ja, genau. Hatte ich Dir nicht deshalb schonmal gesagt, daß sowas wesentlich leichter in Perl oder Python zu machen ist? Weil es da vernünftige Arrays gibt, und auch die Leerzeichen keine Probleme machen?

Wenn Du das in einer der beiden Sprachen machen möchtest (könntest Dir eine aussuchen), könnte ich Dich da durchführen, wenn Du möchtest. Wäre sowieso 'ne gute Sache zu lernen.
Gräfin Klara
Hacker
Hacker
Beiträge: 623
Registriert: 23. Jun 2008, 20:51

Re: bash-Script mit Doppelschleife

Beitrag von Gräfin Klara »

abgdf hat geschrieben: 20. Sep 2020, 14:58 Weil es da vernünftige Arrays gibt, und auch die Leerzeichen keine Probleme machen?
Gib mir Beispiele "vernünftiger", eindimensionaler Perl Arrays (ohne Hash), die einem Array in Bash überlegen wären.
Das wird dir nicht gelingen, weder in Performance noch Anwendung.
Christina
Member
Member
Beiträge: 102
Registriert: 4. Mär 2019, 13:44

Re: bash-Script mit Doppelschleife

Beitrag von Christina »

Jetzt klappt's. Und die Lösung mit zwei Arrays ist kürzer als die mit temp-Dateien und zwei Schleifen.

Code: Alles auswählen

#!/bin/bash

echo -e "FLAC-Zielverzeichnis: \c"
read pathname
suffix="flac"
IFS=$'\n'

fa=()   # filename array A
fb=()   # filename array B
i=0     # array index
fa=($(find . -maxdepth 1 -type f -name "*.$suffix" -printf "%f\n" | sort -f))
fb=($(find $pathname -maxdepth 1 -type f -name "*.$suffix" -printf "%p\n" | sort -f))
for i in ${!fa[@]}; do
  printf "%.2d: %s -> %s\n" "$i" "${fa[i]}" "${fb[i]}"
  metaflac --export-tags-to=- ${fa[i]} | metaflac --remove-all-tags --import-tags-from=- ${fb[i]}
done
exit 0
Super, Danke!
@abgdf Wo ist das Problem?
LG
Christina
Zuletzt geändert von Christina am 20. Sep 2020, 17:20, insgesamt 1-mal geändert.
Gräfin Klara
Hacker
Hacker
Beiträge: 623
Registriert: 23. Jun 2008, 20:51

Re: bash-Script mit Doppelschleife

Beitrag von Gräfin Klara »

Christina hat geschrieben: 20. Sep 2020, 17:08 Jetzt klappt's.
Die Zeilen
fa=() # filename array A
fb=() # filename array B
kannst noch entfernen (war nur Erklärung)

fb=($(find $pathname .... nach
fb=($(find "$pathname" ..

Kürzer geht's nimmer.
Sehr gut
Christina
Member
Member
Beiträge: 102
Registriert: 4. Mär 2019, 13:44

Re: bash-Script mit Doppelschleife

Beitrag von Christina »

Was bedeutet das @ hier als Index im Array?

Code: Alles auswählen

for i in ${!fa[@]}; do
Ist das ein explizit ungültiger Ausdruck in der bash wie der NULL-Pointer in C?
abgdf
Guru
Guru
Beiträge: 3376
Registriert: 13. Apr 2004, 21:15

Re: bash-Script mit Doppelschleife

Beitrag von abgdf »

Christina hat geschrieben: 20. Sep 2020, 17:08@abgdf Wo ist das Problem?
Ach, ich mag die bash halt nicht besonders (Leerzeichenproblematik in Arrays, fehlende oder existierende Whitespace-Zeichen können von Bedeutung sein ('a="a"' - ok, 'a = "a"' nicht), nur eingeschränkte Rückgabewerte von Funktionen, unerwartete Subshells, umständliche Stringfunktionen, wird schnell kryptisch - und ich finde "fi" bescheuert :) ). Ist kein so gutes Tool finde ich, bzw. es gibt inzwischen bessere. Aber wenn Du damit klarkommst und es benutzen willst, wird es schon ok sein.
Zuletzt geändert von abgdf am 20. Sep 2020, 17:51, insgesamt 4-mal geändert.
Gräfin Klara
Hacker
Hacker
Beiträge: 623
Registriert: 23. Jun 2008, 20:51

Re: bash-Script mit Doppelschleife

Beitrag von Gräfin Klara »

Christina hat geschrieben: 20. Sep 2020, 17:36 Was bedeutet das @ hier als Index im Array?

Code: Alles auswählen

for i in ${!fa[@]}; do
Ist das ein explizit ungültiger Ausdruck in der bash wie der NULL-Pointer in C?
@ steht für Array als solches, d.h. liefert immer generelle Informationen zum Array, Beispiel
${!fa[@]} alle indexes, von 0 bis x
${#fa[@]} Gesamtgröße = Anzahl der Elemente (auch das hätten wir verwenden können)
${fa[@]} liefert alle Elemente

usw.

.. wie NULL-Pointer in C?
Nein
Christina
Member
Member
Beiträge: 102
Registriert: 4. Mär 2019, 13:44

Re: bash-Script mit Doppelschleife

Beitrag von Christina »

Gräfin Klara hat geschrieben: 20. Sep 2020, 17:46 ${#fa[@]} Gesamtgröße = Anzahl der Elemente (auch das hätten wir verwenden können)
Also so: (C-ähnliche Notation)

Code: Alles auswählen

len_a=${#fa[@]}
for ((i=0; i<${len_a}; i++)); do
Mit doppelter Klammer ((…)), oder? Funktionieren tut's.

Wie schreibt man eigentlich in der bash die if-Anweisung korrekt? Mit doppelter eckiger Klammer [[…]] ?
Ich habe verschiedene Varianten im www gesehen.

Code: Alles auswählen

len_a=${#fa[@]}
len_b=${#fb[@]}
if [[ $len_a = $len_b ]]; then
  …
else
  printf "Anzahl Dateien unterschiedlich: Quellverzeichnis %d <-> Zielverzeichnis %d.\n" "$len_a" "$len_b"
fi
Funktionieren tut's.
abgdf
Guru
Guru
Beiträge: 3376
Registriert: 13. Apr 2004, 21:15

Re: bash-Script mit Doppelschleife

Beitrag von abgdf »

Christina hat geschrieben: 21. Sep 2020, 20:40Wie schreibt man eigentlich in der bash die if-Anweisung korrekt? Mit doppelter eckiger Klammer [[…]] ?
Das tun wohl die meisten. Es ist wohl eine Abkürzung für:

Code: Alles auswählen

if test $len_a = $len_b; then ...
Was ich lieber verwende, da man dabei wenigstens halbwegs nachvollziehen kann, was da passiert.
Doppelte eckige Klammern, und dann noch notwendige Leerzeichen dazwischen, ohne die es nicht funktioniert ... also ich find's völlig unintuitiv.

Seltsamerweise wird Perl immer vorgehalten, wie häßlich der Code ist. Dabei ist bash-Code noch viel häßlicher. :)

P.S.: Übrigens: "-eq", nicht "=": Du willst ja Zahlen vergleichen, nicht Strings.
In Perl ist es übrigens umgekehrt. Auch toll. Nichtmal einheitlich.
josef-wien
Ultimate Guru
Ultimate Guru
Beiträge: 5534
Registriert: 23. Sep 2008, 17:09

Re: [gelöst] bash-Script mit Doppelschleife

Beitrag von josef-wien »

Ohne Pfad-Angabe ist test ein shell builtin und entspricht [ (ohne Pfad-Angabe ebenfalls ein shell builtin).

[[ ]] ist eine flexiblere Form. Siehe: https://tldp.org/LDP/abs/html/abs-guide ... BLBRACKETS
Christina
Member
Member
Beiträge: 102
Registriert: 4. Mär 2019, 13:44

Re: bash-Script mit Doppelschleife

Beitrag von Christina »

abgdf hat geschrieben: 21. Sep 2020, 23:42 P.S.: Übrigens: "-eq", nicht "=": Du willst ja Zahlen vergleichen, nicht Strings.
In Perl ist es übrigens umgekehrt. Auch toll. Nichtmal einheitlich.
-eq funktioniert auch.

Code: Alles auswählen

if [ $len_a -eq $len_b ]; then

Code: Alles auswählen

if [ "$len_a" -eq "$len_b" ]; then
Integer möchte ich vergleichen. Wie ist es korrekt?
lg Christina
Gräfin Klara
Hacker
Hacker
Beiträge: 623
Registriert: 23. Jun 2008, 20:51

Re: bash-Script mit Doppelschleife

Beitrag von Gräfin Klara »

Christina hat geschrieben: 21. Sep 2020, 20:40

Code: Alles auswählen

len_a=${#fa[@]}
for ((i=0; i<${len_a}; i++)); do
..Funktionieren tut's.
Kein Wunder, ist ja auch korrekt
Ich hätte es folgend geschrieben (C-alike)

Code: Alles auswählen

for((i=0,k=${#fa[@]}; i < k; i++)); do

Christina hat geschrieben: 21. Sep 2020, 20:40 Wie schreibt man eigentlich in der bash die if-Anweisung korrekt? Mit doppelter eckiger Klammer [[…]] ?
Ich habe verschiedene Varianten im www gesehen.
[ .. ] hat historische Gründe. Es läßt sich nicht ändern, nur erweitern, sonst würden Millionen alte scripts nicht mehr funktionieren.
[[ .. ]] ist neu, es bietet mehr und kann auch alles was [ .. ] kann. Denk nicht darüber nach, verwende [[ .. ]]

Christina hat geschrieben: 21. Sep 2020, 20:40

Code: Alles auswählen

len_a=${#fa[@]}
len_b=${#fb[@]}
if [[ $len_a = $len_b ]]; then
  …
else
  printf "Anzahl Dateien unterschiedlich: Quellverzeichnis %d <-> Zielverzeichnis %d.\n" "$len_a" "$len_b"
fi
Funktionieren tut's.
= für Vergleich ist aus der Unix Steinzeit, wird in vielen scripts noch verwendet, kann man nicht ändern, Grund siehe oben.
len_a=${#fa[@]} liefert dir einen integer (Zahl). integers werden mit -eq, -ne, usw. verglichen. [[ $i -eq $k ]];
Wenn du = anwendest, dann werden die Zahlen vor dem Vergleich in strings umgewandelt, diesen Doppelmoppel wollen wir nicht.
Strings testest du auf Gleichheit mit [[ "$str_a" == "$str_b" ]]; also das einfache = streichst du für Vergleiche aus deinem Gedächtnis.

Code: Alles auswählen

if [[ $len_a -eq $len_b ]]; then
  …
elif [[ $len_a -gt $len_b ]]; then
 ...
elif [[ "$str_a" == "$str_b" && $len_a -ne $len_b ]]; then
...
else
  ...
fi
Gruß
Gräfin Klara
Zuletzt geändert von Gräfin Klara am 22. Sep 2020, 12:28, insgesamt 1-mal geändert.
abgdf
Guru
Guru
Beiträge: 3376
Registriert: 13. Apr 2004, 21:15

Re: bash-Script mit Doppelschleife

Beitrag von abgdf »

Christina hat geschrieben: 22. Sep 2020, 10:01-eq funktioniert auch.
Integer möchte ich vergleichen. Wie ist es korrekt?
Vgl. auch "man test".
Christina
Member
Member
Beiträge: 102
Registriert: 4. Mär 2019, 13:44

Re: bash-Script mit Doppelschleife

Beitrag von Christina »

Vielen Dank! :-)
Hier ist nochmal das ganze Script und die (gewünschte) Ausgabe. Ich habe beim Print bei Index statt "$1" noch "$((i+1))" eingefügt, damit die Nummerierung bei 01 statt 00 beginnt. Ich hoffe, das ist im bash-Script so richtig.

Code: Alles auswählen

#!/bin/bash

echo -e "FLAC-Zielverzeichnis: \c"
read destin_path
source_path="."
IFS=$'\n'

fa=($(find $source_path -maxdepth 1 -type f -name "*.flac" -printf "%f\n" | sort -f))
fb=($(find $destin_path -maxdepth 1 -type f -name "*.flac" -printf "%p\n" | sort -f))
len_a=${#fa[@]}
len_b=${#fb[@]}
if [[ $len_a -eq $len_b ]]; then
  for ((i=0; i<${len_a}; i++)); do
    printf "%.2d: %s -> %s\n" "$((i+1))" "${fa[i]}" "${fb[i]}"
    metaflac --export-tags-to=- ${fa[i]} | metaflac --remove-all-tags --import-tags-from=- ${fb[i]}
  done
else
  printf "Anzahl Dateien unterschiedlich: Quellverzeichnis %d <-> Zielverzeichnis %d.\n" "$len_a" "$len_b"
fi
exit 0

# Zeile 13 alternativ:
# i=0
# for i in ${!fa[@]}; do
01: 01. Here You Come Again.flac -> /home/christina/Tascam/Dolly Parton/T063_DAT-Band.flac
02: 02. Baby Come Out Tonight.flac -> /home/christina/Tascam/Dolly Parton/T064_DAT-Band.flac
03: 03. It’s All Wrong, but It’s All Right.flac -> /home/christina/Tascam/Dolly Parton/T065_DAT-Band.flac
04: 04. Me and Little Andy.flac -> /home/christina/Tascam/Dolly Parton/T066_DAT-Band.flac
05: 05. Lovin’ You.flac -> /home/christina/Tascam/Dolly Parton/T067_DAT-Band.flac
06: 06. Cowgirl and the Dandy.flac -> /home/christina/Tascam/Dolly Parton/T068_DAT-Band.flac
07: 07. Two Doors Down.flac -> /home/christina/Tascam/Dolly Parton/T069_DAT-Band.flac
08: 08. God’s Coloring Book.flac -> /home/christina/Tascam/Dolly Parton/T070_DAT-Band.flac
09: 09. As Soon as I Touched Him.flac -> /home/christina/Tascam/Dolly Parton/T071_DAT-Band.flac
10: 10. Sweet Music Man.flac -> /home/christina/Tascam/Dolly Parton/T072_DAT-Band.flac
Wenn jetzt kein Fehler mehr drin ist, habe ich ein schönes Beispiel fürs nächste Script. Learning by doing. :-)
Antworten