staging.inyokaproject.org

for-Schleife für Dateien in Verzeichnis - ich verzweifle

Status: Ungelöst | Ubuntu-Version: Ubuntu 24.04 (Noble Numbat)
Antworten |

kB Team-Icon

Supporter, Wikiteam
Avatar von kB

Anmeldungsdatum:
4. Oktober 2007

Beiträge: 9837

Marc_BlackJack_Rintsch schrieb:

Die Aussage zur rekursiven Funktion finde ich übertrieben.

Ich habe schon manchen Zauberschüler erlebt, der das auch glaubte und sich anschließend wunderte, in welche Untiefen und Probleme er bei der praktischen Umsetzung gelangte.

So eine Funktion ist nicht wirklich kompliziert und auch recht schnell geschrieben.

Aber nicht schnell getestet. Dein erster Entwurf

1
Recurse () []

enthält einige offensichtliche Fehler: Die Prozedur übersieht z.B. reguläre Dateien neben Ordnern und es gibt einige Situationen, in denen sie Syntaxfehler produziert.

rklm Team-Icon

Projektleitung

Anmeldungsdatum:
16. Oktober 2011

Beiträge: 13242

rklm schrieb: [...]

Mit find:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
find Ablage -type f -name \*.flac -exec sh -c '
unset dir

for flac; do
  d="$(dirname "$flac")"

  if [ "$dir" != "$d" ]; then
    # first one!
    dir="$d"
    echo "Processing: $flac ..."
  fi
done' -- {} +

Immer noch ungetestet.

Marc_BlackJack_Rintsch Team-Icon

Ehemalige
Avatar von Marc_BlackJack_Rintsch

Anmeldungsdatum:
16. Juni 2006

Beiträge: 4735

@kB Welche Dateien werden übersehen? Was für Syntaxfehler?

UlfZibis

(Themenstarter)

Anmeldungsdatum:
13. Juli 2011

Beiträge: 3351

kB schrieb:

Hor bitte auf mit diesen unfairen Angriffen, unnötigen Spitzen ...

Wer austeilt und mit entehrenden Du-Botschaften um sich wirft, sollte auch einstecken können.

Allerdings sehe ich es als Missbrauch, wenn man für Aufgaben, welche die spezifischen Fähigkeiten von find – insbesondere das rekursive Durchsuchen von Verzeichnisbäumen – nicht benötigen, dennoch find verwendet, bloß weil man eine simple Schleife vermeiden will.

Wenn das der Grund für die kommentarlose Löschung meiner angeblich "vandalistisch" eingebrachten Beispiele für 3 Arten von Verkettung von mehreren Operationen auf Funde war, warum hast Du dann nicht einfach höflich nach diesbezüglicher Änderung gefragt? Eine solche ist im Handumdrehen machbar, verlängert aber die Beispiele um 2..3 Terme, was der anderen Forderung nach Kürze allerdings entgegenlaufen würde. Wie hier im Thread – der nicht ohne Grund so länglich geworden ist – ging es um einen möglichst einfachen Rahmen zur "Ausführung komplizierterer verketteter Operationen" mit per find gefundenen Dateien. Solche Beispiele fehlen IMHO im Artikel find und der Verweis, dass man das "ganz einfach" mit einem Bash-Skript per for bewerkstelligen kann, entbehrt jeder Grundlage, wie man in hiesigem Thema sieht.

Leider verstellst Du Dich als zu doof, um diesen Punkt zu begreifen.

Und das ist kein "unfairer Angriff"?

Nochmal: Hör auf mit diesem unfairen Gebaren! (s.o.)

Ebenfalls!

UlfZibis

(Themenstarter)

Anmeldungsdatum:
13. Juli 2011

Beiträge: 3351

kB schrieb:

find . -type d -execdir find {} -maxdepth 1 -type f -name '*.flac' -print -quit \; 
  1. Wo kann ich da die eingangs erwähnte "kompliziertere Operation" unterbringen?

Diese wichtigste Frage bitte auch beantworten.

  1. ... liefert folgendes Ergebnis: […]

Eine Möglichkeit wäre:

find . -type d -execdir find {} -maxdepth 1 -type f -name '*.flac' -print -quit \; | while read ; do echo ${REPLY#./} ; done 

Liefert weiterhin nicht die hier benötigten relativen Pfade ab aktuellem Verzeichnis zu den Dateien.

kB Team-Icon

Supporter, Wikiteam
Avatar von kB

Anmeldungsdatum:
4. Oktober 2007

Beiträge: 9837

UlfZibis schrieb:

kB schrieb: […] >>> Wo kann ich da die eingangs erwähnte "kompliziertere Operation" unterbringen? Diese wichtigste Frage bitte auch beantworten.

Das habe ich doch anhand der beispielhaften Bearbeitung des Dateinamens gezeigt! In der Schleife zwischen do und done kannst Du alles mit der Datei machen, deren Namen in der Schleife ja bekannt ist.

[…] Liefert weiterhin nicht die hier benötigten relativen Pfade ab aktuellem Verzeichnis zu den Dateien.

Das -print von find liefert genau das. Die Zeichen „./“ am Anfang, die Du ja weggeschnitten haben wolltest, bezeichnen genau das aktuelle Verzeichnis, ab dem gesucht und gefunden wurde. Entscheide Dich mal, ob Du das brauchst oder nicht – beides geht nicht.

Wenn Du statt des dafür üblichen und funktionalen Punktes den Namen des Ordners haben willst, musst Du das selbst übersetzen. Das ist simple Verarbeitung von Zeichenketten und man kann es beispielsweise mit der Shell oder mit sed machen. Der Name des aktuellen Verzeichnisses steht in der Variablen PWD als absoluter Pfad. Das hat aber nun wirklich nichts mehr mit find, oder mit For-Schleifen oder dem Thema dieses Diskussionsfadens zu tun.

Marc_BlackJack_Rintsch Team-Icon

Ehemalige
Avatar von Marc_BlackJack_Rintsch

Anmeldungsdatum:
16. Juni 2006

Beiträge: 4735

@kB Es geht nicht um ./ am Anfang oder nicht, sondern das man mit dem Ergebnis nix anfangen kann, weil da was fehlt um überhaupt an die Dateien heran zu kommen:

1
2
3
$ find . -type d -execdir find {} -maxdepth 1 -type f -name '*.flac' -print -quit \; | while read ; do echo ${REPLY#./} ; done 
Album2/01 titel1.flac
Album1/02-titel2.flac

Auch mit ./ davor ist das so nutzlos weil diese Dateien ja vom Skript aus gesehen nicht in Album2/01 titel1.flac und Album1/02-titel2.flac liegen:

1
2
$ ls 'Album2/01 titel1.flac'
ls: cannot access 'Album2/01 titel1.flac': No such file or directory

Die Datei soll ja verarbeitet werden, und dazu braucht man den Pfad dort hin. Danach war gefragt.

Und ich wäre auch immer noch interessiert daran welche Dateien da bei mir angeblich nicht berücksichtigt werden und welche Syntaxfehler auftreten können, und was so die erwähnten offensichtlichen Fehler sind. Ich würde gerne daraus lernen.

UlfZibis

(Themenstarter)

Anmeldungsdatum:
13. Juli 2011

Beiträge: 3351

Marc_BlackJack_Rintsch schrieb:

@kB Es geht nicht um ./ am Anfang oder nicht, sondern das man mit dem Ergebnis nix anfangen kann,

💡

kB Team-Icon

Supporter, Wikiteam
Avatar von kB

Anmeldungsdatum:
4. Oktober 2007

Beiträge: 9837

Marc_BlackJack_Rintsch schrieb:

@kB Es geht nicht um ./ am Anfang oder nicht, sondern das man mit dem Ergebnis nix anfangen kann, weil da was fehlt um überhaupt an die Dateien heran zu kommen […]

Danke für die Aufklärung! Damit ist das Problem leicht zu lösen: Wenn man das Arbeitsverzeichnis nicht wechseln will, muss man -exec anstatt --execdir verwenden:

$find . -type d -exec find {} -maxdepth 1 -type f -name '*.flac' -print -quit \; | while read ; do ls "$REPLY" ; done
'./Various Artists/They are Playing Our Song/12 - June In January.flac'
"./Various Artists/Finnischer Tango Tule Tanssimaan/01 - Siks' oon mä suruinen.flac"
…

Statt ls kann man natürlich jedes andere Programm zu weiteren Verarbeitung verwenden.

kB Team-Icon

Supporter, Wikiteam
Avatar von kB

Anmeldungsdatum:
4. Oktober 2007

Beiträge: 9837

Marc_BlackJack_Rintsch schrieb:

[…] Und ich wäre auch immer noch interessiert daran welche Dateien da bei mir angeblich nicht berücksichtigt werden und welche Syntaxfehler auftreten können, und was so die erwähnten offensichtlichen Fehler sind. Ich würde gerne daraus lernen.

Versteh' ich, aber in diesem Thread wäre das sachfremd und deshalb eine Themenentführung. Vielleicht an anderer Stelle, aber meine Zeit wird momentan von anderen Themen absorbiert.

Marc_BlackJack_Rintsch Team-Icon

Ehemalige
Avatar von Marc_BlackJack_Rintsch

Anmeldungsdatum:
16. Juni 2006

Beiträge: 4735

@kB: Warum ist das diskutieren über eine Antwort auf die Frage des Themas hier sachfremd? In der Zeit diese Nicht-Antwort zu verfassen, hättest Du auch einfach schreiben können was die offensichtlichen Fehler sind. Erst gezeigten Code so kritisieren, dann aber nicht konkret zu sagen was die angeblich offensichtlichen Probleme sind, ist etwas unschön. Um das mal nett zu formulieren. 🫤

user_unknown

Avatar von user_unknown

Anmeldungsdatum:
10. August 2005

Beiträge: 17630

shiro schrieb:

Wenn du nur die erste .flac Datei verarbeiten willst, warum machst du dann nicht folgendes?

$ # Erzeuge Spielwiese
$ mkdir -p Ablage/{Album{1,4},Interpret} Ablage/Interpret/Album{2..3}
$ touch Ablage/Album1/{123.jpg,01-titel1.flac,02-titel2.flac}
$ touch Ablage/Interpret/Album{2,3}/{123.jpg,01\ titel1.flac,02\ titel2.flac}
# ...

Sehr schön, Shiro, sehr brauchbar.

Anderer Ansatz:

1
2
3
4
for d in $(find -name *.flac -exec dirname {} ";" | uniq ) ; do ls $d/*.flac | head -1 ; done 
./Ablage/Album1/01-titel1.flac
./Ablage/Interpret/Album2/01 titel1.flac
./Ablage/Interpret/Album3/01 titel1.flac

Prämisse: Keine Zeilenumbrüche in Dateinamen.

Die Lösung, die ich bevorzuge, ist, alle Leerzeichen aus Dateinamen zu eliminieren - das Minuszeichen lässt sich am besten tippen und mehrere, aufeinanderfolgende Leerzeichen, braucht man auch nicht.

UlfZibis

(Themenstarter)

Anmeldungsdatum:
13. Juli 2011

Beiträge: 3351

user_unknown schrieb:

shiro schrieb:

Wenn du nur die erste .flac Datei verarbeiten willst, warum machst du dann nicht folgendes?

$ # Erzeuge Spielwiese
$ mkdir -p Ablage/{Album{1,4},Interpret} Ablage/Interpret/Album{2..3}
$ touch Ablage/Album1/{123.jpg,01-titel1.flac,02-titel2.flac}
$ touch Ablage/Interpret/Album{2,3}/{123.jpg,01\ titel1.flac,02\ titel2.flac}
# ...

Sehr schön, Shiro, sehr brauchbar.

Allerdings wäre folgendes gefordert:

$ # Erzeuge Spielwiese
$ mkdir -p Ablage/{Album{1,4},Interpret} Ablage/Interpret/Album{2..3}
$ touch Ablage/{Album1,Interpret/Album2}/{123.jpg,01-titel1.flac,02-titel2.flac}
$ touch Ablage/Interpret/Album3/{123.png,01\ titel1.mp3,02\ titel2.mp3}

Anderer Ansatz:

1
for d in $(find -name *.flac -exec dirname {} ";" | uniq ) ; do ls $d/*.flac | head -1 ; done

Prämisse: Keine Zeilenumbrüche in Dateinamen.

Sehr schön kompakt.

UlfZibis

(Themenstarter)

Anmeldungsdatum:
13. Juli 2011

Beiträge: 3351

Für einen statistischen Überblick komme ich erst mal mit folgendem gut klar:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
dirs=0;
flacdirs=0;
files01=0;
while read -r -d '' dir; do
  ((dirs++))
  while read -r -d '' file; do
#    echo "$dir";
    ((flacdirs++));
    if [ -f "$dir"/01*.flac ]; then
      ((files01++));
      echo 01 `ls -1 "$dir"/01*.flac`;
    else
      echo XX $file;
    fi;
  done < <(find "$dir" -maxdepth 1 -iname "*.flac" -print0 -quit | sort -z);
done < <(find Ablage -mindepth 1 -type d -print0 | sort -z)
echo Number of dirs total: $dirs;
echo Number of dirs with flac files: $flacdirs;
echo Number of 01* flac files: $files01;

kB schrieb:

find . -type d -exec find {} -maxdepth 1 -type f -name '*.flac' -print -quit \; | while read ; do ls "$REPLY" ; done

Das taugt für obiges leider nicht, da durch -exec und die Pipe immer ein neuer Prozess gestartet wird, in dem die globalen Zählvariablen nicht zugreifbar sind. Sonst aber auch ein schöner Ansatz.

kB Team-Icon

Supporter, Wikiteam
Avatar von kB

Anmeldungsdatum:
4. Oktober 2007

Beiträge: 9837

UlfZibis schrieb:

Für einen statistischen Überblick […] Das taugt für obiges leider nicht […]

Vielleicht solltest Du Dir für zukünftige Supportanfragen angewöhnen, gleich zu Beginn die Aufgabe vollständig zu beschreiben, anstatt in Salamitaktik für jeden Lösungsvorschlag ein weiteres Detail als Begründung nachzuliefern, warum Du den Vorschlag leider nicht verwenden kannst.

Das würde jedenfalls Frust bei Deinen Helfern vermeiden.