Ich verwende Bash, um einige Informationen von Audacious an Conky zur Anzeige zu übermitteln (einschließlich Albumcover). Ich erhalte den Pfad zum Verzeichnis der Musikdatei von Audacious und versuche dann, per cd in dieses Verzeichnis zu wechseln, um folder.jpg zu finden. Wenn es gefunden wird, bereite ich es zur Anzeige vor. Leider kann ich mich nicht auf „wohlgeformte“ Pfadnamen verlassen. Keiner von ihnen hat ein Problem vom Terminal aus, aber die Auswertungen, die Bash macht … Es versinkt in doppelten Leerzeichen ( ) ' / und wahrscheinlich anderen, obwohl das aktuelle Setup damit klarzukommen scheint – ok. Hier ist die relevante Funktion:
GetArt ()
{
file_path=`audtool --current-song-tuple-data file-path` # get the path to the song
file_path=$(eval echo "${file_path}") # pre-expand to full path
cd "${file_path}"
if [[ ! -e "folder.jpg" ]]; # if no art work found
then
cp ~/Work/vinyl.png /tmp/cover.png # put in placeholder
else
convert "${file_path}""/folder.jpg" -resize 120x120 /tmp/cover.png # ready for showing
fi
}
Irgendwelche Ideen, oder wäre es einfacher, die Drahtbürste rauszuholen und den Rost von meinem C-Compiler zu entfernen?
Ich habe es mit doppelten Anführungszeichen, einfachen Anführungszeichen, Backticks und sogar einer Konstruktion wie dieser versucht:
code=$code \"\$filename\""
aber bisher scheint nichts richtig zu funktionieren. Glücklicherweise schlägt es ziemlich fehl, weil stattdessen nur das Ersatzbild „Kann Art nicht finden“ angezeigt wird, aber manchmal rülpst alles über stderr, bis zum nächsten Song – oder Album.
Antwort1
Sie können file_path="${file_path/#~/$HOME}"
mit erweiternNurDie ~
.
Soweit ich sagen kann,Tilde-Erweiterungist die einzige Art von Erweiterung, die auf die Ausgabe von angewendet werden muss audtool --current-song-tuple-data file-path
. Darüber hinaus tritt nur ein spezieller Fall der Tilde-Notation auf: Wenn der von Audacious verwendete Pfad mit dem Home-Verzeichnis des Benutzers beginnt, der Audacious ausführt, wird dieser Teil des Pfads ~
in der Ausgabe von durch ein ersetzt audtool
. Da dieaudacious
Undaudtool
Die Manpages geben dazu keine Auskunft. Ich habe versucht, audtool
Ausgabepfade mit der ~username
Form einer Tilde-Erweiterung zu erhalten, aber glücklicherweise scheint nicht einmal das zu passieren. Ich sage „glücklicherweise“, weil das bedeutet, dass die Situation ziemlich einfach ist.
Da die einzige Transformation, die an der Ausgabe dieses Befehls vorgenommen werden muss, audtool
darin besteht, ein führendes Zeichen ~
durch den Pfad des Home-Verzeichnisses des Benutzers zu ersetzen, können Sie einfach Code in Ihr Skript schreiben, der diese Erweiterung selbst durchführt und den Pfad ansonsten unverändert lässt. Sie haben festgestellt, dass Dateinamen von Audiodateien, die Sie möglicherweise abspielen, Zeichen enthalten können, die von der Shell speziell behandelt werden, undWenn Sie Dateien abspielen, die von anderen Personen benannt wurden,kann sogar zu einer Sicherheitslücke führenin Ihrem Skript. Indem Sie die Shell keinen beliebigen, nicht vertrauenswürdigen Text ausführen – oder gar erweitern – lassen, vermeiden Sie dieses Problem vollständig.
Es gibt mehrere Möglichkeiten, ~
sich zu erweitern. Ich schlage vor:
file_path="$(audtool --current-song-tuple-data file-path)" # might need tilde expansion
file_path="${file_path/#~/$HOME}" # do the tilde expansion, if needed
Dadurch wird die eine Transformation, die möglicherweise erforderlich ist, manuell durchgeführt. Insbesondere wenn die Ausgabe von audtool
mit einem beginnt ~
, wird es durch das Home-Verzeichnis des Benutzers ersetzt, das durch Überprüfen des Wertes der HOME
Variablen ermittelt wird. Wenn die Ausgabe nicht mit einem beginnt ~
, wird keine Erweiterung durchgeführt.
${file_path/#~/$HOME}
Beachten Sie , dass dieser Ansatznichtwäre richtig, wenn es als Versuch verwendet würde, alle Formen der Tilde-Erweiterung zu simulieren, da es in der ~username
Form (und in einigen der anderen, weniger bekannten Formen) falsche Ersetzungen vornehmen würde. Solange Pfade in der Ausgabe jedoch audtool
nur die Tilde-Notation verwenden, wenn einfach das Home-Verzeichnis des aktuellen Benutzers bezeichnet wird – was meines Erachtens der Fall ist –, dann ist dieser AnsatzIstfür diese Pfade angemessen und richtig.
So funktioniert es:
- Allgemein,Bash wird erweitert
${parameter/pattern/string}
in den Wert vonparameter
, aber mitder Teil, der passtpattern
ersetzt durchstring
. Wenn kein Teil dem Muster entspricht, wird der genaue Wert vonparameter
verwendet. - Wenn
pattern
mit einem führenden geschrieben wird#
, kann es nur ab dem Anfang des Wertes von abgeglichen werdenparameter
. (Es gibt auch andere Zeichen#
, die an dieser Stelle sinnvoll sind: ein%
würde erfordern, dass das Muster am Anfang abgeglichen wird.Ende, und a/
würde dazu führen, dass das Muster so oft abgeglichen und ersetzt wird, wie es vorkommt, und nicht höchstens einmal.) ~
hat in einem Muster keine besondere Bedeutung und wird daher wörtlich als ein abzugleichendes und zu ersetzendes Zeichen behandelt.
SehenParametererweiterungfür Details.
Beachten Sie, dass der Code, den ich geschrieben habe, nichts tut, um den Fall einer audtool
leeren Ausgabe zu behandeln, wie es passiert, wenn gerade kein Lied abgespielt wird (oder, wieSimon Sudler erwähnte, wenn ein Fehler auftritt). Es wird jedoch bei einer leeren Ausgabe nicht unterbrochen und behindert auch nicht die nachfolgende Verarbeitung. Wenn Sie diesen Fall also abdecken möchten, können Sie das immer noch tun.
Abschließend möchte ich erwähnen, dass ich zwei Unterschiede übergangen habe, die meiner Meinung nach für Ihren Anwendungsfall unwichtig sind:
- Da
audtool
die Pfade von aus Audacious stammen, müssten Sie, wenn Sie die bizarre Situation versuchen würden, Audacious als ein Benutzer und als ein anderer Benutzer auszuführenaudtool
– und Sie D-Bus irgendwie so konfiguriert hätten, dass dies funktioniert –, darauf achten,~
auf das Home-Verzeichnis eines anderen Benutzers zu verweisen als des Benutzers, der das Skript ausführt. - Technisch gesehen ist die Tilde-Erweiterung für den aktuellen Benutzer (die in einer Shell mit
~
allein oder unmittelbar gefolgt von erfolgt/
) nichtganzentspricht"$HOME"
. Shells können versuchen, den seltsamen Fall zu behandeln, in demHOME
nicht gesetzt ist. Bash versucht dies zu behandeln und trotzdem eine korrekte Erweiterung zu erzeugen. Ich bezweifle jedoch, dass Sie sich für diesen Zweck für die Unterscheidung interessieren. SieheTilde-Erweiterungfür Details.
Antwort2
Die Neuzuweisung der file_path
Variablen ist nicht notwendig. Es können zwei Anzeichen auftreten, die das Skript beschädigen könnten:
- Die Variable ist leer, da sie
audtool
einen Fehler zurückgibt - Gibt
audtools
ein Verzeichnis zurück, das Leerzeichen enthält. audtool
Includes~
für das Home-Verzeichnis
Hier ein Vorschlag zur Lösung dieser Probleme:
GetArt ()
{
file_path="$(audtool --current-song-tuple-data file-path)"
file_path="$(readlink -f "$(bash -c "echo $file_path")")"
if [[ ! -d $file_path ]]; then
echo "error: $file_path does not exists"
exit 1
fi
folder_jpg="$file_path/folder.jpg"
if [[ ! -e "$folder_jpg" ]]; then
cp ~/Work/vinyl.png /tmp/cover.png
else
convert "$folder_jpg" -resize 120x120 /tmp/cover.png
fi
}
Dies "$(command)"
behandelt die Leerzeichen im Ordnernamen (falls welche vorhanden sind). Verwenden Sie es nicht cd
innerhalb eines Skripts, wenn Sie es nicht benötigen. Es ist immer eine gute Idee zu prüfen, ob die Rückgabezeichenfolge ein Verzeichnis ist. Das Arbeiten mit dem absoluten Pfad ist in den meisten Fällen besser und verhindert die Ausführung von Befehlen im falschen Ordner.
Hinweise zur ~
Erweiterung in der Bash:
Die Erweiterung von ~
wird von der Bash gehandhabt und readlink -f
hilft hier daher nicht. Daher ~
muss die Variable, die das enthält, ohne Anführungszeichen ausgeführt werden, um erweitert zu werden (ich habe das Skript aktualisiert). Dies kann natürlich in einer einzigen Zeile gehandhabt werden ...
# expansion from current bash
$ set -x; readlink -f ~; set +x
+ readlink -f /home/user
/home/user
+ set +x
# expansion will not work, with quoted ~
$ set -x; readlink -f '~'; set +x
+ readlink -f '~'
/home/user/~
+ set +x
# expansion from un-quoted ~ with sub-shell
$ set -x; readlink -f "$(bash -c "echo ~")"; set +x
++ bash -c 'echo ~'
+ readlink -f /home/user
/home/user
+ set +x