• Willkommen im Linux Club - dem deutschsprachigen Supportforum für GNU/Linux. Registriere dich kostenlos, um alle Inhalte zu sehen und Fragen zu stellen.

[gelöst] bash-Script mit Doppelschleife

Christina schrieb:
.. statt "$1" noch "$((i+1))" eingefügt ..hoffe, das ist im bash-Script so richtig.
absolut richtig


Christina schrieb:
Code:
#!/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
Wenn jetzt kein Fehler mehr drin ist ...
Einges wäre noch verbesserungswürdig, aber
dein script erfüllt die Aufgabe, es ist für Dritte leicht verständlich und es entspricht dem neuesten Stand von Bash.
Von mir bekommst du ein Befriedigend.

Gruß
Gräfin Klara
 

abgdf

Guru
Tja ...

Das löst aber nicht die Probleme mit der verd****** bash.

Beispiel: Bereitet ein Verzeichnis namens "test" mit folgendem Skript vor:
Code:
#!/bin/bash
mkdir test
touch "./test/test1"
touch "./test/test2"
touch "./test/hallo welt"
Und dann laßt dieses Skript laufen, das dem von Christina nachempfunden ist:
Code:
#!/bin/bash

fa=($(find "./test" -maxdepth 1 -type f -name "*" -printf "%f\n"))
len_fa=${#fa[@]}

echo $len_fa

for ((i=0; i<${len_fa}; i++)); do
    echo "$i    ${fa[i]}"
done
Ihr erhaltet folgende Ausgabe:
Code:
4
0    test1
1    test2
2    hallo
3    welt
Und das ist mal wieder nicht das Ergebnis, das man haben will. Sondern man würde Folgendes wollen (und nicht bekommen):
Code:
3
0    test1
1    test2
2    hallo welt

------

In Perl dagegen mal wieder kein Problem:
Code:
#!/usr/bin/perl
use warnings;
use strict;

my @fa = <./test/*>;

print $#fa + 1 . "\n";
for (my $i = 0; $i <= $#fa; $i++) {
    print "$i    $fa[$i]\n";
}
 

abgdf

Guru
Gräfin Klara schrieb:
Weil du
IFS=$'\n'
vergessen hast
Ach so. Wieder was gelernt. :thumbs:
abgdf schrieb:
Absoluter overkill für eine so simple Aufgabe
Das schrieb robi auch schonmal: "Benutze kein Perl, viel zu groß".
Aber wozu? Mein Rechner ist (schon wieder) alt, und trotzdem macht es ihm überhaupt nichts aus. Wenn ich dagegen "awk" zur Datenverarbeitung bemühe, das kleiner ist (wie robi das tut), macht es mir eine Menge aus. Dauert einfach viel länger, wenn man's nicht gewohnt ist.
Insofern bin ich der Meinung: Wir haben heute die Ressourcen, und es ist kein Problem, sie auch einzusetzen. Die 80er waren gut, aber manche Probleme von damals haben wir glücklicherweise nicht mehr. Mangelnde Speicherkapazität und Prozessor-Leistung gehören dazu.
 
abgdf schrieb:
..
Insofern bin ich der Meinung: Wir haben heute die Ressourcen, und es ist kein Problem, sie auch einzusetzen.
Für diesen sanften Hügel nehme ich die Sandalen mit Grip,
du bevorzugst die schweren Bergstiefel mit Stahleinlagen.
Hinauf kommen wir beide,
 
Das Entscheidende ist doch das jeder das nehmen kann womit er, und gegebenenfalls sein Umfeld, am Besten zurecht kommt oder was im am besten gefällt.
 
A

Anonymous

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

Gräfin Klara schrieb:
[ .. ] 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 [[ .. ]]

Dies Aussage greift aber sehr kurz.

Das eine ist intern in der Bash verbaut "[[ ... ]]"
man bash schrieb:
[[ expression ]]
Return a status of 0 or 1 depending on the evaluation of the conditional expression expression. Expressions are composed of the primaries described below under
CONDITIONAL EXPRESSIONS. Word splitting and pathname expansion are not performed on the words between the [[ and ]]; tilde expansion, parameter and variable
expansion, arithmetic expansion, command substitution, process substitution, and quote removal are performed. Conditional operators such as -f must be unquoted
to be recognized as primaries.
....
Das andere "[ ....... " ist nichts weiter als ein Hardlink (bzw heute oft eine anderes kompilierte Form) von /usr/bin/test

Code:
robi@linux001 >which [
/usr/bin/[
robi@linux001 >ls -il /usr/bin/[
1053488 -rwxr-xr-x 1 root root 39704 17. Mär 2014  /usr/bin/[
robi@linux001 >ls -il /usr/bin/test
1055508 -rwxr-xr-x 1 root root 35616 17. Mär 2014  /usr/bin/test
Nachweisen kann man das zum Beispiel wenn man mal in den Binärcode reinschaut, hier mal als Beispiel ein Bereich wo die HELP Infomationen von beiden Binärdateien gegenüberstellt.

Code:
robi@linux001 >strings /usr/bin/[  | grep FILE
  FILE1 -ef FILE2   FILE1 and FILE2 have the same device and inode numbers
  FILE1 -nt FILE2   FILE1 is newer (modification date) than FILE2
  FILE1 -ot FILE2   FILE1 is older than FILE2
  -b FILE     FILE exists and is block special
  -c FILE     FILE exists and is character special
  -d FILE     FILE exists and is a directory
  -e FILE     FILE exists
  -f FILE     FILE exists and is a regular file
  -g FILE     FILE exists and is set-group-ID
  -G FILE     FILE exists and is owned by the effective group ID
  -h FILE     FILE exists and is a symbolic link (same as -L)
  -k FILE     FILE exists and has its sticky bit set
  -L FILE     FILE exists and is a symbolic link (same as -h)
  -O FILE     FILE exists and is owned by the effective user ID
  -p FILE     FILE exists and is a named pipe
  -r FILE     FILE exists and read permission is granted
  -s FILE     FILE exists and has a size greater than zero
  -S FILE     FILE exists and is a socket
  -u FILE     FILE exists and its set-user-ID bit is set
  -w FILE     FILE exists and write permission is granted
  -x FILE     FILE exists and execute (or search) permission is granted
Except for -h and -L, all FILE-related tests dereference symbolic links.
robi@linux001 >strings /usr/bin/test  | grep FILE
  FILE1 -ef FILE2   FILE1 and FILE2 have the same device and inode numbers
  FILE1 -nt FILE2   FILE1 is newer (modification date) than FILE2
  FILE1 -ot FILE2   FILE1 is older than FILE2
  -b FILE     FILE exists and is block special
  -c FILE     FILE exists and is character special
  -d FILE     FILE exists and is a directory
  -e FILE     FILE exists
  -f FILE     FILE exists and is a regular file
  -g FILE     FILE exists and is set-group-ID
  -G FILE     FILE exists and is owned by the effective group ID
  -h FILE     FILE exists and is a symbolic link (same as -L)
  -k FILE     FILE exists and has its sticky bit set
  -L FILE     FILE exists and is a symbolic link (same as -h)
  -O FILE     FILE exists and is owned by the effective user ID
  -p FILE     FILE exists and is a named pipe
  -r FILE     FILE exists and read permission is granted
  -s FILE     FILE exists and has a size greater than zero
  -S FILE     FILE exists and is a socket
  -u FILE     FILE exists and its set-user-ID bit is set
  -w FILE     FILE exists and write permission is granted
  -x FILE     FILE exists and execute (or search) permission is granted
Except for -h and -L, all FILE-related tests dereference symbolic links.

Damit ist beides etwas komplett anderes, das eine ist intern in der Bash verbaut und wird sofort ohne Umwege genutzt, (und kann wenn ich eine andere Shell als die Bash verwende anders funktionieren) und das andere ist ein eigenes Programm dazu muss erst ein neuer Prozess mittels forc erstellt werden, dann der Binärcode der Datei in den neuen Prozess geladen werden und dann der neue Prozess dort gestartet werdeb. Das ist genau so als wenn Subprozesse erstellt werden wie für jedes andere im Scriptcode verwendete (Basch)externe Tool auch. zB grep, sed, cat , find ..... .
Und kostet damit Zeit und Ressourcen und macht zB in großen Schleifen die Abarbeitung von Scripts langsam.

Auch die möglichen Optionen/Operatoren und Möglichkeiten sind recht verschieden.
Damit sollte man sich schon bewusst sein, das das [[ ]] und [ ] nicht wirklich das Gleiche oder nur Historisch-und-Nachfolger ist.

IF ist nun auch nicht unbedingt nur für [, [[ oder test bestimmt. In der Manpage von bash findet man die Definition.
man bash" if list; then list; [ elif list; then list; schrieb:
... [ else list; ] fi
The if list is executed. If its exit status is zero, the then list is executed. Otherwise, each elif list is executed in turn, and if its exit status is zero,
the corresponding then list is executed and the command completes. Otherwise, the else list is executed, if present. The exit status is the exit status of the
last command executed, or zero if no condition tested true.
ich kann also hier eine Abfrage (if) auf das (End)Ergebniss einer ganzen Latte von Befehlen machen, Wenn der letzte Befehl in der Liste den Status 0 zurückgibt dann wird die Befehlsliste hinter then ausgeführt, sonst hinter else

Code:
robi@linux001 >if ls ; ls -l ; ls -il | grep "File4" ; then echo vorhanden ; else echo nicht vorhanden ; fi
File1  File2  File3  File4  File5  File6
insgesamt 0
-rw-rw-r-- 1 puppe users 0 25. Sep 14:26 File1
-rw-rw-r-- 1 puppe users 0 25. Sep 14:26 File2
-rw-rw-r-- 1 puppe users 0 25. Sep 14:26 File3
-rw-rw-r-- 1 puppe users 0 25. Sep 14:26 File4
-rw-rw-r-- 1 puppe users 0 25. Sep 14:26 File5
-rw-rw-r-- 1 puppe users 0 25. Sep 14:26 File6
3021659 -rw-rw-r-- 1 puppe users 0 25. Sep 14:26 File4
vorhanden
hier wird als "TEST" zuerst "ls" ausgeführt, anschließend "ls -l" und anschließend "ls -il | grep File4"
Ausgewertet wird der Rückgabewert von grep und da grep was gefunden hat wird der then-Zweig durchlaufen, in dem natürlich dann auch wieder jede Menge Befehle in einer Liste stehen könnten.

Von da her ist if-then-else-fi in der Bash etwas mächtiger als in vielen Programmiersprachen, und man kann damit durchaus Programmabläufe programmieren, wo man sich extrem schwer tut dieses in eine andere Programmiersprache eins-zu-eins zu übersetzen. Allerdings werden hier die Möglichkeiten der Bash meist an dieser Stelle gar nicht richtig ausgenutzt, weil natürlich jeder "Programmierer" irgendwie hier in allgemein gültigen logischen Algorithmen denkt und damit selten die Möglichkeiten und Stärken von einzelnen Programmiersprachen aus Grundlage für die Optimierung eines Programmablauf zugrundelegt.

robi
 

josef-wien

Ultimate Guru
robi schrieb:
Das andere "[ ....... " ist nichts weiter als ein Hardlink (bzw heute oft eine anderes kompilierte Form) von /usr/bin/test
Da muß ich mich doch glatt selbst zitieren: https://linux-club.de/forum/viewtopic.php?p=792514#p792514
Und dann noch den Anfang des Abschnitts "CONDITIONAL EXPRESSIONS" schreiben:
man bash schrieb:
Conditional expressions are used by the [[ compound command and the test and [ builtin commands to test file attributes and perform string and arithmetic comparisons.
/usr/bin/[ und /usr/bin/test sind - wie von Dir erwähnt - normale Programme.
 
robi schrieb:
Gräfin Klara schrieb:
[ .. ] 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 [[ .. ]]

Dies Aussage greift aber sehr kurz.

Die Erklärung zu [ -> test ist unter Bash Archäologie.
Interessant? Ja! wertvoll? Nein!

robi schrieb:
Auch die möglichen Optionen/Operatoren und Möglichkeiten sind recht verschieden.
Damit sollte man sich schon bewusst sein, das das [[ ]] und [ ] nicht wirklich das Gleiche oder nur Historisch-und-Nachfolger ist.
Natürlich verschieden, das erfordert aber nicht die Kenntnis beider Regeln.
Gräfin Klara schrieb:
[[ .. ]] ist neu, es bietet mehr und kann auch alles was [ .. ] kann. Denk nicht darüber nach, verwende [[ .. ]]
Dabei bleibe ich

Gruß
Gräfin Klara
 
OP
Christina

Christina

Moderator
Teammitglied
Gräfin Klara schrieb:
Die Erklärung zu [ -> test ist unter Bash Archäologie.
Interessant? Ja! wertvoll? Nein!
Und mehr als [[ … ]] verwirrt mich im Moment nur.

Ich habe noch eine Frage zu ls & find im bash-Script:
Um die getaggten Flac-Dateien anschließend umzubenennen, genügt ja einfach nach der Zeile mit metaflac:
Code:
mv ${fb[i]} "$destin_path/${fa[i]}"
Unschön aber aber ohne Fehler ist der doppelte Schrägstrich im String,
wenn ich bei $destin_path bereits einen abschließenden Schrägstrich habe.

Jetzt überlege ich, wie ich immer nur einen Schrägstrich hinten am Verzeichnis bekommen kann.
Code:
ls -dF /home/christina/Tascam/Dolly Parton/
/home/christina/Tascam/Dolly Parton//
So geht es also nicht.
Mit welchem Kommando kann man das //-Problem am Pfadende korrekt lösen (auch wenn es trotzdem funktioniert)?

Ganz radikal und einfach wäre, wenn ich die fertigen Dateien ins Quellverzeichnis verschiebe, aber das möchte ich nicht.
Code:
mv -f ${fb[i]} ${fa[i]}
 
Oben steht:
Code:
read destin_path
Kann bzw. sollte sein:
Code:
read -r
destin_path="${REPLY%/}"
if [[ ! -d "$destin_path" ]]; then
  printf "Pfad %s existiert nicht\n" "$destin_path"
  exit 1
fi
...
REPLY ist eine interne Variable für read.
destin_path="${REPLY%/}" extrahiert aus dem string $REPLY alles nach destin_path, außer ein eventuell folgendes /
 

abgdf

Guru
Christina schrieb:
Jetzt überlege ich, wie ich immer nur einen Schrägstrich hinten am Verzeichnis bekommen kann.
Code:
ls -dF /home/christina/Tascam/Dolly Parton/
/home/christina/Tascam/Dolly Parton//
So geht es also nicht.
Indem Du in dem ls-Befehl das "-F" wegläßt?

Schrägstriche sind normalerweise nicht Teil des Verzeichnisnamens.
josef-wien schrieb:
/usr/bin/[ und ... sind - wie von Dir erwähnt - normale Programme.
Cool, wußte ich auch nicht. :thumbs:

Offenbar nennen einige ihre Programme "[" und ihre Verzeichnisse "v//". :D
 
OP
Christina

Christina

Moderator
Teammitglied
abgdf schrieb:
Indem Du in dem ls-Befehl das "-F" wegläßt?
Das klappt dann auch nicht im bash-Script:
Code:
ls -d /home/christina/Tascam/Dolly\ Parton
/home/christina/Tascam/Dolly Parton
-> Gar kein abschließendes /.
 
Gräfin Klara schrieb:
destin_path="${REPLY%/}" extrahiert aus dem string $REPLY alles nach destin_path, außer ein eventuell folgendes /
Das meine ich. :)
Die Lösung musste ja sehr einfach sein. Das wird überall benötigt, wo Pfadangaben in Shellskripten benutzt werden.
Und destin_path="${REPLY#/}" entfernt einen eventuellen führenden /, habe ich eben gelesen:
Quora.com: What does the percent symbol mean on Bash?
Den Exit-Code habe ich jetzt auch beim Vergleich der Anzahl der Flac-Dateien drin. Dann kann ich das per echo $? abfragen.
Code:
#!/bin/bash

echo -e "FLAC-Zielverzeichnis: \c"
read -r
source_path="."
destin_path="${REPLY%/}"
if [[ ! -d "$destin_path" ]]; then
    printf "Pfad \"%s\" existiert nicht.\n" "$destin_path"
    exit 1
fi

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 -ne $len_b ]]; then
    printf "Anzahl Dateien unterschiedlich: Quellverzeichnis %d <-> Zielverzeichnis %d.\n" "$len_a" "$len_b"
    exit 1
fi

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]}
    mv ${fb[i]} "$destin_path/${fa[i]}"
done
exit 0
Die Stringverkettung per " $…/$… " ganz unten beim mv passt auch so, oder? Das ist kein historischer Code?
In C würde ich spontan sprintf nehmen.
 

abgdf

Guru
Schrägstich gehört nicht zum Verzeichnisnamen.
Code:
mkdir "test/"
ls -d test/
ls -d test
Ausgabe:
Code:
test/
test
 
OP
Christina

Christina

Moderator
Teammitglied
Der abschließende / kennzeichnet ein Verzeichnis. Das habe ich als Anfängerin so gelesen und mir das gleich angewöhnt.
Manche Programme verlangen den trailing '/' bei Pfadangaben sogar. Das steht dann auch im manual page.
 
Christina schrieb:
..
Den Exit-Code habe ich jetzt auch beim Vergleich der Anzahl der Flac-Dateien drin. Dann kann ich das per echo $? abfragen.
Perfekt!
Christina schrieb:
Die Stringverkettung per " $…/$… " ganz unten beim mv passt auch so, oder? Das ist kein historischer Code?
Alles ok!

Christina schrieb:
Der abschließende / kennzeichnet ein Verzeichnis. Das habe ich als Anfängerin so gelesen und mir das gleich angewöhnt.
Das solltest du dir abgewöhnen. @abgdf hat hier völlig Recht. Trailing / kennzeichnet nicht einen Verzeichnisnamen.
Sollte ein Programm das so verlangen, dann ist die Frage an den Programmierer "Was soll der Blödsinn" berechtigt.

Noch eine Kleinigkeit:
Code:
for ((i=0; i<${len_a}; i++)); do
Diese Zeile erschwert die Arbeit des Interpreters enorm, die Variable ${len_a} so darzustellen, ist ein Bug.
Wie du oben bei ${REPLY%/} gesehen hast, kann man mit einem { (opening brace) eine spezielle Aufgabe anfordern.
Das kann sein Extrahieren, Löschen, Ändern, usw. von Inhalten in dieser Variable. Der Interpreter geht also nach
einem brace in seine Tiefen und sucht die geforderte Aufgabe. ${len_a} beinhaltet aber keine.
Diese unnötige Leistung muß der Interpreter bei jedem Durchlauf der loop erbringen. i < $len_a; wäre hier richtig.

Gruß
Gräfin Klara
 
OP
Christina

Christina

Moderator
Teammitglied
Vielen Dank an euch für die Info!
Die for-Schleifenbedingung habe ich geändert. Ich hatte das letzten Mo. so von for i in ${!fa[@]}; do übernommen.
Jetzt habe ich eine schöne Scriptvorlage fürs nächste Mal!
Ein bash-Script hat wirklich Vorteile gegenüber C.
lg Christina
Wird in der bash bei der Variablendeklaration eigentlich nach Zeichen, Ganzzahl und Gleitkomma unterschieden?
 

abgdf

Guru
Christina schrieb:
Wird in der bash bei der Variablendeklaration eigentlich nach Zeichen, Ganzzahl und Gleitkomma unterschieden?
Nicht (so streng) wie in C.
bash-Variablen können ja sowohl Strings als auch Zahlen speichern.
In Perl nennt man diese flexiblen Variablen "Skalarvariablen" oder "Skalare".
In dem wohl umfangreichsten Dokument zur bash, in dem man manchmal nachschlagen muß, dem "Advanced Bash-Scripting Guide", finde ich diesen Begriff nicht, aber in der Sache ist es eigentlich dasselbe:

https://tldp.org/LDP/abs/html/untyped.html

Christina schrieb:
Jetzt habe ich eine schöne Scriptvorlage fürs nächste Mal!
Ein bash-Script hat wirklich Vorteile gegenüber C.
bash ist gut für die Arbeit mit Dateien oder wenn man spezielle Kommandozeilenprogramme aufrufen will wie eben "metaflac".
Wenn man dagegen mehr Daten verarbeiten will (z.B. die Daten in Dateien), oder wenn man viel mit Strings und Listen arbeiten will, wäre Perl die bessere Wahl (natürlich gäbe es da auch eine "system()"-Funktion, um hier und da auch einen speziellen Shell-Befehl wie "metaflac" abzusetzen).
So ist es auch entstanden: Der Erfinder von Perl (Larry Wall) hatte viele Strings zu verarbeiten, und das war ihm in C (mit "strcpy()", usw.) zu umständlich. Deshalb mischte er einige Elemente aus der bash (und sed und awk) und C und formte daraus eine eigene (interpretierte) Programmiersprache (wobei er den Perl-Interpreter wiederum in C schrieb, er gab C also nicht völlig auf, im Gegenteil).
Also, wenn Du C kennst, und bash, dann würdest Du mit Perl sehr viel Spaß haben.
Es ist die eigentliche Sprache, die die Vorteile gegenüber C während der Programmierung hat. Die bash bezieht sich halt mehr auf die Arbeit mit Dateien.

Die meisten Linux-User lernen die Sprachen wohl in der Reihenfolge "erst bash, dann Perl, dann C" kennen.
Aber "erst C, dann bash, und dann ggf. Perl" ginge natürlich auch. ;)
 
OP
Christina

Christina

Moderator
Teammitglied
Vielen Dank!

Ich habe jetzt noch die Übergabe des Zielverzeichnisses per Kommandozeilenparameter "$1" eingebaut:
Code:
#!/bin/bash

source_path="."
if [[ $# -eq 1 ]]; then
    destin_path="${1%/}"
else
    echo -e "FLAC-Zielverzeichnis: \c"
    read -r
    destin_path="${REPLY%/}"
fi
if [[ ! -d "$destin_path" ]]; then
    printf "Pfad \"%s\" existiert nicht.\n" "$destin_path"
    exit 1
fi

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 -ne $len_b ]]; then
    printf "Anzahl Dateien unterschiedlich: Quellverzeichnis %d <-> Zielverzeichnis %d.\n" "$len_a" "$len_b"
    exit 1
fi

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]}
    mv ${fb[i]} "$destin_path/${fa[i]}"
done
exit 0
 
Oben