ubuntuusers.de

Diverse Quoting-Probleme

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

TK87

Anmeldungsdatum:
8. Juli 2019

Beiträge: 301

Wohnort: Aachen

glaskugel schrieb:

Ich habe die erlaubten Zeichen geändert und es funktioniert nicht mit "-"

if grep -q '[/\:-|]' <<<$2; then

Das Minuszeichen muss escaped werden, wenn es nicht am Anfang steht.

if grep -q '[-/\:|]' <<<$2; then

kB Team-Icon

Supporter, Wikiteam
Avatar von kB

Anmeldungsdatum:
4. Oktober 2007

Beiträge: 10197

Wohnort: Münster

glaskugel schrieb:

[…]

#! /bin/bash -e

Was bewirkt das "-e"?

Mit der Option -e bricht die bash ein laufendes Skript ab, sobald dieses einen Fehler (d.h. Rückgabe ≠ 0) verursacht.

Ohne die Option läuft das Skript mit den dann vermutlich fehlerhaften Daten weiter.

glaskugel

(Themenstarter)

Anmeldungsdatum:
8. Juli 2010

Beiträge: 4224

if grep -q '[/\:\-|]' <<<$2; then

Funktioniert noch immer nicht, aber so:

if grep -q '[-/\:|]' <<<$2; then

Soll mir recht sein. Gibt es da noch andere Zeichen bei denen man aufpassen muss?

Mit der Option -e bricht die bash ein laufendes Skript ab

Vielen Dank, nichts für mich, gibt immer wieder unbedeutende Schönheitsfehler bei unerwarteten, aber unwichtigen Änderungen.

TK87

Anmeldungsdatum:
8. Juli 2019

Beiträge: 301

Wohnort: Aachen

glaskugel schrieb:

Gibt es da noch andere Zeichen bei denen man aufpassen muss?

Nur wenn man andere Optionen wie etwa -E verwendet. Das Minus bedeutet in der Mitte eben "bis", also...

grep '[a-z]'

würde z.B. auf alle Kleinbuchstaben von a bis z zutreffen.

glaskugel

(Themenstarter)

Anmeldungsdatum:
8. Juli 2010

Beiträge: 4224

würde z.B. auf alle Kleinbuchstaben von a bis z zutreffen.

Danke, so kenne ich das auch.

Wenn es nicht zu kompliziert wird, dann versuche ich doch noch mit dem Dateimuster die Aufnahme-App zu erkennen.

  • Fieldrecorder: 260111-213736.wav

  • ASR: 2026_01_11_21_47_10.wav

  • NeutronRecorder: Record_[11-01-2026]_[21_56_46].wav

  • Axet-Audiorecorder (opensource): 2026-01-11 22.04.05.wav

Also da gibt es auch Leerzeichen im Dateinamen.

Den Axet-Recorder gibt es nur mehr bei https://gitlab.com/axet/android-audio-recorder, F-Droid hat den vermutlich rausgeworfen, weil er seit 10 Jahren nicht mehr gepflegt wird. Der kann aber extrem viel und funktioniert eigentlich problemlos, verwendet aber nur 1 Musiker, die anderen haben was gekauft. Die Frage ist, wie lange Google noch erlaubt, dass der installiert wird.

Wie schon geschrieben, die Standard-App ist Fieldrecorder.

Ich brauche regex so selten, dass ich wieder anstehe.

Also so in der Richtung:

If Muster = ..., dann app = Appname

Letztlich geht es darum, das Aufnahmejahr für die mp3-Metadaten zu definieren, aber das sollte dann leicht mit cut gehen.

PS:

Man könnte das natürlich holprig mit grep machen:

  • Kommt kein _ im Dateinamen vor, dann ist es der Fieldrecorder

  • Kommt ein Leerzeichen vor, dann ist es der Axet

  • Steht Record im Namen, dann ist es der Neutron

  • Kommt _ 5x vor ist es der ASR, oder überhaupt wenn keines davor zutrifft

kB Team-Icon

Supporter, Wikiteam
Avatar von kB

Anmeldungsdatum:
4. Oktober 2007

Beiträge: 10197

Wohnort: Münster

glaskugel schrieb:

[…] Wenn es nicht zu kompliziert wird, dann versuche ich doch noch mit dem Dateimuster die Aufnahme-App zu erkennen.

Das ist sogar sehr einfach, wenn man die Sprachmittel der bash zur Erkennung von Mustern Shell/Glob und zur Verarbeitung von Zeichenketten verwendet.

  • Fieldrecorder: 260111-213736.wav

  • ASR: 2026_01_11_21_47_10.wav

  • NeutronRecorder: Record_[11-01-2026]_[21_56_46].wav

  • Axet-Audiorecorder (opensource): 2026-01-11 22.04.05.wav

[…] Letztlich geht es darum, das Aufnahmejahr für die mp3-Metadaten zu definieren

Mein Ansatz (ungetestet) dafür:

case $Dateiname
  in (*[0-9]' '[0-9]*)   Recorder=Axet    Jahr=${Dateiname::4}
  ;; (*[0-9]-[0-9]*)     Recorder=Field   Jahr=20${Dateiname::2}
  ;; (Record_*)          Recorder=Neutron Jahr=${Dateiname#*[} Jahr=${Jahr%]_*} Jahr=${Jahr:5}
  ;; (*_*)               Recorder=ASR     Jahr=${Dateiname::4}
  ;; (*)                 unset Recorder Jahr
esac

Voraussetzung ist natürlich, dass die Dateinamen regelmäßig so aussehen, wie Du es hier beschreibst.

shiro Team-Icon

Supporter

Anmeldungsdatum:
20. Juli 2020

Beiträge: 1449

Mein Ansatz (ungetestet) dafür:

Schöne übersichtliche Fallunterscheidung.

Ich würde allerdings die "Neutron" Prüfung vor die "Field" Prüfung setzen, da sonst auf "Record_*" nicht mehr geprüft wird, weil ja "Field" vorher matched.

glaskugel

(Themenstarter)

Anmeldungsdatum:
8. Juli 2010

Beiträge: 4224

Das ist sogar sehr einfach

Ja, solange man nicht zu kompliziert denkt. Die Case-Bedingungen sind klar. Man muss die globs nur als Lösung sehen 😉

https://wiki.ubuntuusers.de/Shell/Glob/ habe ich mir angesehen und die längeren Folgelinks nur überflogen und dann doch Dinge nicht verstanden.

Jahr=${Dateiname::4}

Was bedeuten die : bzw. wo kann ich das nachlesen? Ich kann das erahnen, möchte es aber richtig wissen.

Dateiname="Record_[11-01-2026]_[21_56_46].wav"
Jahr=${Dateiname#*[} Jahr=${Jahr%]_*} Jahr=${Jahr:5}

Da verstehe ich die Syntax kaum. Du grenzt also in Schritten ein,

Zuerst wirfst du alles bis [ raus

Dann fällt alles ab der 1. ] weg

Wo lese ich die Syntax nach? Ich hätte da irgendwie mit cut rumgebastelt. Verstehe ich die globs doch zu wenig oder liegt das einfach an # und % ?

Warum machst du das:

Jahr=${Jahr:5}

Das stimmt nicht. Grundsätzlich hat das Jahr 4 Zeichen. Es kommt ein "-" davor.

Ich verstehe die folgende Lösung nicht:

$ echo $Jahr
11-01-2026

$ Jahr=${Jahr:6}
$ echo $Jahr
2026

PS: Ich habe den Rest noch nicht getestet, dürfte aber passen.

Ich habe noch ein Problem beim sortieren

for input in `find "$1" -type f -regex ".*\.wav$" | sort` ; do

Ich vermute mal einfach kann man die verschiedenen Dateien nicht nach Darum und Zeit sortieren. Die Dateien sind auch noch in verschiedenen Unterverzeichnissen. Das ist aber nicht sehr realistisch, könnte aber vorkommen, wenn man die verschiedenen Apps testet. Normalerweise wird alles mit der gleichen App aufgenommen. Der originale Dateiname soll irgendwie erhalten bleiben, der kommt in den mp3-Kommentar. Das habe ich mir gerade für den case-Test überlegt.

2 Schleifen?

1. Schleife benennt um und setzt am Anfang des Dateinamens eine Sortierzeit.

2. Schleife sucht dann nochmals, aber dann habe ich noch immer das Problem, dass die Dateien in verschiedenen Verzeichnissen sind.

find gibt ja den Pfad an, es dürfte nur nach Dateiname sortiert werden.

seahawk1986

Anmeldungsdatum:
27. Oktober 2006

Beiträge: 11300

Wohnort: München

Ich würde da so langsam mal an eine nettere Skriptsprache denken - z.B. Python:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#!/usr/bin/python3
from datetime import datetime
import fileinput

format_strings = {
    "Fieldrecorder": "%y%m%d-%H%M%S.wav",
    "ASR": "%Y_%m_%d_%H_%M_%S.wav",
    "NeutronRecorder": "Record_[%d-%m-%Y]_[%H_%M_%S].wav",
    "Axet": "%Y-%m-%d %H.%M.%S.wav"
}

def parse_line(line: str) -> tuple[str, datetime]:
    for name, format_str in format_strings.items():
        try:
            return name, datetime.strptime(line, format_str)
        except Exception:
            pass
    else:
        raise ValueError(f"unknown filename format for '{line}'")
  

def main():
    results: list[tuple[str, datatetime]] = []
    for line in fileinput.input():
        line = line.strip()
        try:
            name, dt = parse_line(line.strip())
        except ValueError as e:
            print(e)
        else:
            results.append((name, dt))
            #print(f"{line} -> {dt.year} ({name})")
        
    for name, dt in sorted(results, key=lambda r: (r[1], r[0])):
        print(f"{dt} ({name})")

if __name__ == '__main__':
    main()
$ python3 test.py << EOF
260111-213736.wav
2026_01_11_21_47_10.wav
Record_[11-01-2026]_[21_56_46].wav
2026-01-11 22.04.05.wav
EOF
2026-01-11 21:37:36 (Fieldrecorder)
2026-01-11 21:47:10 (ASR)
2026-01-11 21:56:46 (NeutronRecorder)
2026-01-11 22:04:05 (Axet) 

shiro Team-Icon

Supporter

Anmeldungsdatum:
20. Juli 2020

Beiträge: 1449

Was bedeuten die : bzw. wo kann ich das nachlesen?

RTFM. Einfach mal ein "man bash" machen und lesen. Siehe:

$ man bash | grep '${parameter'
       ${parameter}
       ${parameter:-word}
       ${parameter:=word}
       ${parameter:?word}
       ${parameter:+word}
       ${parameter:offset}
       ${parameter:offset:length}
       ${parameter#word}
       ${parameter##word}
       ${parameter%word}
       ${parameter%%word}
       ${parameter/pattern/string}
       ${parameter//pattern/string}
       ${parameter/#pattern/string}
       ${parameter/%pattern/string}
       ${parameter^pattern}
       ${parameter^^pattern}
       ${parameter,pattern}
       ${parameter,,pattern}
       ${parameter@operator}
                      within  ${parameter}  expansions  enclosed   in   double
$ 

Oder

man bash | sed -n '/^ *Parameter Expansion/,/^ *Command/p'
man bash | less -p '\$\{p'

glaskugel

(Themenstarter)

Anmeldungsdatum:
8. Juli 2010

Beiträge: 4224

Ich würde da so langsam mal an eine nettere Skriptsprache denken - z.B. Python:

Das würde ich liebend gerne, seit Jahren, aber das lassen die persönlichen Umstände nicht zu. Ich bin schon froh zur Zeit wieder ein wenig mehr am PC zu tun, das kann abrupt jeden Tag enden.

RTFM. Einfach mal ein "man bash" machen

Zufällig gerade vor ein paar Tagen nachgelesen, aber dann das richtige finden und verstehen, ist eine andere Sache.

Geändert: Ich scheitere gerade an einem Codeschnipsel von einem uralten Script, normalerweise bestehen meine Dateinamen aus US-ASCII und keinen Leerzeichen und da ist das kein Problem. In diesem Fall kommt aber ein Leerzeichen vor und ist ein Kriterium zur Erkennung.

Mein Frage ist, ob das bei Dateien mit Leerzeichen korrekt ist:

find "$1" -type f -regex ".*\(flac$\|wav$\)" -print0 | while read -d $'\0' file
do
	echo "<""$file"">"
done

Ich hatte diese Syntax mal verwendet um wav-Dateien umzubennen. Ist eigentlich eh alles vorhanden, man muss sich nur an das Script erinnern.

Das funktioniert grundsätzlich solange ich kein sort brauche. Ich verwende case so wie ich es gewohnt bin, Außerdem mag ich die Backticks lieber, auch wenn überholt. So kommt es immer wieder zu einer Mischung, sorry.

find "$1" -type f -regex ".*\(flac$\|wav$\)" -print0 | while read -d $'\0' dateiname_voll
do
	echo
	dateiname=`basename "$dateiname_voll"`
	
	case $dateiname	in
		(Record_*)
			recorder="NeutronRecorder"
			sortfile="$tempdir"/${dateiname:14:4}${dateiname:11:2}${dateiname:8:2}${dateiname:21:2}${dateiname:24:2}${dateiname:27:2}_${recorder}_${dateiname}
			cp -v "$dateiname_voll" "$sortfile"
		;; 
		(*[0-9]' '[0-9]*)
  			recorder="AxetAudioRecorder"
  			sortfile="$tempdir"/${dateiname::4}${dateiname:5:2}${dateiname:8:2}${dateiname:11:2}${dateiname:14:2}${dateiname:17:2}_${recorder}_${dateiname}
  			cp -v "$dateiname_voll" "$sortfile"
  		;;
  		(*[0-9]T[0-9]*)
			recorder="AxetAudioRecorder-T"
  			sortfile="$tempdir"/${dateiname::8}${dateiname:9:6}_${recorder}_${dateiname}
  			cp -v "$dateiname_voll" "$sortfile"
		;;
		(*[0-9]-[0-9]*)
			recorder="FieldRecorder"
			sortfile="$tempdir"/20${dateiname::6}${dateiname:7:6}_${recorder}_${dateiname}
			cp -v "$dateiname_voll" "$sortfile"
		;;
		(*_*)
			recorder=ASR
			sortfile="$tempdir"/${dateiname::4}${dateiname:5:2}${dateiname:8:2}${dateiname:11:2}${dateiname:14:2}${dateiname:17:2}_${recorder}_${dateiname}
			cp -v "$dateiname_voll" "$sortfile"
		;;
		(*)
			echo
			echo "unbekannter Recorder: Abbruch"
			echo
			echo "erkannt werden die Standard-Dateimuster von ASR, Axet, FieldRecorder, NeutronRecorder"
			echo "(Record_*)"
			echo "(*[0-9]' '[0-9]*)"
			echo "(*[0-9]T[0-9]*)"
			echo "(*[0-9]-[0-9]*)"
			echo "(*_*)"
			echo
			echo "Entferne"
			echo "$dateiname_voll"
			echo "Abbruch mit Strg-C beenden"
			echo
			sleep 999999999999999999999
		;;
	esac
done

Da ist also noch ein Würgaround. Wie breche ich das Script aus der Schleife komplett ab?

Wichtig ist auch die Reihenfolge von case, sonst wird der Neutron als Fieldrecorder erkannt. Eine auswählbare Alternative der Axet-Syntax wurde vorsorglich hinzugefügt.

Damit ist auch das Problem mit der Sortierung bzw. der Track-Nummerierung gelöst, wenn sich die Audio-Dateien in verschiedenen Verzeichnissen befinden. Die werden nach /tmp in ein Verzeichnis kopiert und sind nach dem nächsten Neustart weg.

Unsicher bin ich mir noch, ob die folgende Syntax ok ist.

find "$tempdir" -type f -regex ".*\(flac$\|wav$\)" | sort | while read -r input
do

	echo
	echo "========================================================"
	echo "Starte $input"
	echo
	originalfile=`basename "$input" | cut -d_ -f3-`
	titel=`echo "$originalfile" | sed -e 's/\.[^.]*$//'`
	track3="00$i"
	yeartag=`basename "$input" | cut -c1-4`
	recorder=`basename "$input" | cut -d"_" -f2`
	kommentar="Original "`basename "$originalfile"`" | $recorder"
	mp3dir="$output_dir""/$artistname_file""/$yeartag-$albumname_file"
	if [ ! -d "$mp3dir" ] ; then
		mkdir -p "$mp3dir"
	fi
	mp3file="$track3""-$titel""-$artistname_file""-$yeartag""-$albumname_file"
	mp3file=`echo "$mp3file" | cut -c1-59`.mp3
	mp3file="$mp3dir""/$mp3file"

	#lame --vbr-new -V1 --id3v2-utf16 --tn $i --tt "$titel" --ty $yeartag --tl "$albumname" --ta "$artistname" --tc "$kommentar" "$input" -o "$mp3file" # erzeugt ID3 version v2.3
	
	lame -V1 --vbr-new "$input" -o "$mp3file"
	eyeD3 --force-update --encoding=utf8 --to-v2.4 -n $i -t "$titel" -Y $yeartag -A "$albumname" -a "$artistname" --comment=::"$kommentar" "$mp3file" # erzeugt ID3 version v2.4

	echo
	let i=i+1

done

So funktioniert das jetzt mehr oder weniger bis auf

mp3file=`echo "$mp3file" | cut -c1-59`.mp3

Wenn da japanisch oder kyrillisch dabei ist, dann funktioniert das nicht. Vermutlich liegt das an der Schreibrichtung bei Japanisch. Fehler kommt bei kyrillisch nach japanisch. Aber das ist mir jetzt egal.

Marc_BlackJack_Rintsch Team-Icon

Ehemalige
Avatar von Marc_BlackJack_Rintsch

Anmeldungsdatum:
16. Juni 2006

Beiträge: 4773

Wohnort: Berlin

@glaskugel: Wenn die persönlichen Umstände es zulassen Bash + alle möglichen Werkzeuge und zusätzliche Sprachen/Variationen zu lernen und wieder zu lernen was man davon im Laufe der Zeit vergisst, dann lassen die auch zu eine andere Programmiersprache zu lernen.

Das wird ja üblicherweise empfohlen weil es letztlich einfacher ist, als dieses Shell-Skript-Gewürge, das dauernd irgend was magisches macht, wo man gegen anquoten muss, nur Zeichenketten kennt, und da dann ”Sonderzeichen” die Probleme machen. Sonderzeichen in Anführungszeichen, weil das leicht irre ist, dass Leerzeichen schon etwas Besonderes mit Folgen sind, auf die man achten muss.

sort kennt die -z beziehungsweise --zero-terminated-Option. Man braucht auf -print0 also nicht zu verzichten, falls man danach ein sort in der Pipeline haben möchte.

Antworten |