staging.inyokaproject.org

find mit OR

Status: Ungelöst | Ubuntu-Version: Kubuntu 22.04 (Jammy Jellyfish)
Antworten |

michahe

Anmeldungsdatum:
12. Dezember 2013

Beiträge: 874

Hallo,

folgender Code funktioniert:

1
2
3
4
5
CountFiles=$(find "$TempDir" -type f -iname "*.mp3" | wc -l)
find -type f -iname "*.mp3" -printf "%f\n" | sort | while read FILE
do
...
done

Wie muss ich die Zeilen 1 und 2 erweitern, um nicht nur '.mp3' sondern auch '.ogg' zu finden?

Danke, Michael

verdooft

Anmeldungsdatum:
15. September 2012

Beiträge: 4450

man find
[...]
OPERATOREN
[...]
Ausdruck1 -o Ausdruck2
              oder; Ausdruck2 wird nicht ausgewertet, falls Ausdruck1 wahr ist

Also:

-iname "*.mp3" -o -iname "*.ogg"

seahawk1986

Anmeldungsdatum:
27. Oktober 2006

Beiträge: 11278

Alternativ könnte man das auch mit einem regulären Ausdruck machen:

find -regex '.*\.\(mp3\|ogg\)' 

rklm Team-Icon

Projektleitung

Anmeldungsdatum:
16. Oktober 2011

Beiträge: 13242

verdooft schrieb:

-iname "*.mp3" -o -iname "*.ogg"

Vorsicht, wenn da noch mehrere Kriterien im Spiel sind. Dann muss man zwingend klammern, z.B.:

1
find "$TempDir" -type f \( -iname '*.mp3' -o -iname '*.ogg' \) -ls

michahe schrieb:

1
2
3
4
5
CountFiles=$(find "$TempDir" -type f -iname "*.mp3" | wc -l)
find "$TempDir" -type f -iname "*.mp3" -printf "%f\n" | sort | while read FILE
do
...
done

Es gibt da noch eine robustere Art das zu machen, indem man \0 (ein Byte mit 0) als Trenner benutzt bzw. zum Zählen nicht die Dateinamen ausgibt.

1
2
3
4
5
6
files=$(find "$TempDir" -type f -iname '*.mp3' -printf . | wc -c)

find "$TempDir" -type f -iname '*.mp3' -print0 | sort -z | while read -d '' file
do
...
done

Ich würde aber den find nicht zwei Mal laufen lassen - zum einen wegen der überflüssigen Arbeit, zum anderen wegen der Konsistenz. Wenn sich der Inhalt des Dateisystems ändert, dann können der Zähler und die verarbeiteten Dateien differieren.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
files=$(mktemp)
trap 'rm -f "$files"'

find "$TempDir" -type f \( -iname '*.mp3' -o -iname '*.ogg' \) -print0 | sort -z >|"$files"
count=$(xargs -r0 -a "$files" sh -c 'echo $#' --)
# wenn viele Dateien erwartet:
count=$(xargs -r0 -a "$files" sh -c 'echo $#' -- | awk '{s+=$1} END {print s}')

xargs -r0 -a "$files" command

# oder
while read -d '' file; do
...
done <"$files"

# oder, wenn man die Anzahl erst hinterher braucht, gleich im `while`-Block die Dateien zählen

Bearbeitet von rklm:

Argument zu "-type" fehlte

Bearbeitet von rklm:

Und da fehlte noch ein "$TempDir".

michahe

(Themenstarter)

Anmeldungsdatum:
12. Dezember 2013

Beiträge: 874

Danke für alle Vorschläge. Ich habe versucht, das umzusetzen, bin aber in allen Ansätzen gescheitert; Eure Lösungen sind so hochwertig, dass ich sie nicht verstehe und nicht für meine Belange umbauen kann. Aber besonders die Ausführungen von rklm haben wichtige Punkte, ich möchte also

  1. Die Liste der .mp3 oder .ogg.Files mit regex ermitteln, mein Code ist falsch und sort fehlt auch noch:

Files=$(find -regex "$TempDir" -type f -iname '.*\.\(mp3\|ogg\)')

2. Die Zeilenzahl dieser Liste ermitteln, vielleicht

CountFiles=$Files | wc -l)

3. Diese Liste mit While .. Do .. While zeilenweise durchlaufen, vielleicht

While read Files
do
...
done

Blöd nur, wenn schon die erste Zeile (auch in den vielen anderen getesteten Varianten) bei mir nicht funktioniert ...

rklm Team-Icon

Projektleitung

Anmeldungsdatum:
16. Oktober 2011

Beiträge: 13242

Am besten fängt man mit einem Schritt an und baut das Skript unter kontinuierlichem Testen immer weiter aus. Es hilft auch ein set -x am Anfang des Skriptes, weil Du dann siehst, welche Befehle mit welchen Argumenten ausgeführt werden.

Ich habe auch noch mal meinen Code angeschaut und ein paar Kleinigkeiten repariert. Du müsstest mal auf die Fehlermeldungen schauen, die Du bei Deinen letzten Versuchen bekommen hast. Da fehlen teilweise Dinge wie eine öffnende Klammer und die Anordnung der Argumente für find ist falsch. Siehe die Manpage. Und Du hast Probleme mit Groß- und Kleinschreibung.

seahawk1986

Anmeldungsdatum:
27. Oktober 2006

Beiträge: 11278

michahe schrieb:

Danke für alle Vorschläge. Ich habe versucht, das umzusetzen, bin aber in allen Ansätzen gescheitert; Eure Lösungen sind so hochwertig, dass ich sie nicht verstehe und nicht für meine Belange umbauen kann. Aber besonders die Ausführungen von rklm haben wichtige Punkte, ich möchte also

  1. Die Liste der .mp3 oder .ogg.Files mit regex ermitteln, mein Code ist falsch und sort fehlt auch noch:

Files=$(find -regex "$TempDir" -type f -iname '.*\.\(mp3\|ogg\)')

-iname macht etwas anderes als -regex - wenn du unabhängig von Groß- und Kleinschreibung matchen willst, kannst du -iregex verwenden - für eine Liste von Dateinamen bietet es sich an einen Array zu nutzen:

1
readarray -d '' FileList < <(find "$TempDir" -type f -iregex '.*\.\(mp3\|ogg\)' -print0)

2. Die Zeilenzahl dieser Liste ermitteln, vielleicht

CountFiles=$Files | wc -l)

Wenn man wie oben einen Array erstellt, kann man abfragen, wie viele Elemente er enthält:

1
CountFiles=${#FileList[@]}

3. Diese Liste mit While .. Do .. While zeilenweise durchlaufen, vielleicht

While read Files
do
...
done

Auch das funktioniert mit Arrays in der Bash sehr bequem:

1
2
3
4
for file in "${FileList[@]}"
do
    echo "do something with $file"
done

michahe

(Themenstarter)

Anmeldungsdatum:
12. Dezember 2013

Beiträge: 874

Danke seahawk1986,

Deine Lösung konnte ich gut nachvollziehen und erfolgreich umsetzen. Mir fehlt noch die Sortierung des Arrays, wobei in den Strings je Zeile Leer- und Sonderzeichen vorkommen können.

EDIT:: So funktioniert es zumindest (mit einem zusätzlichen Befehl):

readarray -td '' FileList < <(printf '%s\0' "${FileList[@]}" | sort -z)

rklm Team-Icon

Projektleitung

Anmeldungsdatum:
16. Oktober 2011

Beiträge: 13242

Was willst Du eigentlich mit den gefundenen Dateien machen?

seahawk1986

Anmeldungsdatum:
27. Oktober 2006

Beiträge: 11278

michahe schrieb:

EDIT:: So funktioniert es zumindest (mit einem zusätzlichen Befehl):

readarray -td '' FileList < <(printf '%s\0' "${FileList[@]}" | sort -z)

Das kannst du auch gleich in den oberen Befehl reinpacken (wobei ggf. für sort noch ein zusätzliches -n sinnvoll sein könnte, wenn nicht alle Zahlen in den Dateinamen mit führenden Nullen auf die gleiche Länge gebracht wurden:

readarray -td '' FileList < <(find "$TempDir" -type f -iregex '.*\.\(mp3\|ogg\)' -print0 | sort -nz) 

michahe

(Themenstarter)

Anmeldungsdatum:
12. Dezember 2013

Beiträge: 874

Danke, seahawk1986,

Das kannst du auch gleich in den oberen Befehl reinpacken (wobei ggf. für sort noch ein zusätzliches -n sinnvoll sein könnte, wenn nicht alle Zahlen in den Dateinamen mit führenden Nullen auf die gleiche Länge gebracht wurden:

readarray -td '' FileList < <(find "$TempDir" -type f -iregex '.*\.\(mp3\|ogg\)' -print0 | sort -nz) 

Ich hatte schon | sort in der readarray Zeile, aber mir fehlte wohl -td. Jetzt ist alles erledigt. Danke!

Antworten |