Wenn ich eine Bash-Eingabeaufforderung öffne und Folgendes eingebe:
$ set -o xtrace
$ x='~/someDirectory'
+ x='~/someDirectory'
$ echo $x
+ echo '~/someDirectory'
~/someDirectory
Ich hatte gehofft, dass die fünfte Zeile oben gegangen wäre + echo /home/myUsername/someDirectory
. Gibt es eine Möglichkeit, dies zu tun? In meinem ursprünglichen Bash-Skript wird die Variable x tatsächlich aus Daten aus einer Eingabedatei über eine Schleife wie die folgende gefüllt:
while IFS= read line
do
params=($line)
echo ${params[0]}
done <"./someInputFile.txt"
Trotzdem bekomme ich ein ähnliches Ergebnis mit dem echo '~/someDirectory'
statt echo /home/myUsername/someDirectory
.
x='~'; print -l ${x} ${~x}
. Ich gab auf, nachdem ichbash
eine Weile im Handbuch durchgeblättert hatte .Antworten:
Der POSIX-Standard schreibt eine Worterweiterung in der folgenden Reihenfolge vor (Hervorhebung ist meine):
Der einzige Punkt, der uns hier interessiert, ist der erste: Wie Sie sehen, wird die Tilde-Erweiterung vor der Parametererweiterung verarbeitet:
echo $x
, es ist keine Tilde zu finden, also geht es weiter.echo $x
,$x
wird gefunden und erweitert und die Kommandozeile wirdecho ~/someDirectory
.~
, bleibt das Zeichen unverändert.Durch die Verwendung der Anführungszeichen beim Zuweisen der
$x
haben Sie ausdrücklich darum gebeten, die Tilde nicht zu erweitern und wie ein normales Zeichen zu behandeln. Eine Sache, die oft übersehen wird, ist, dass Sie in Shell-Befehlen nicht die gesamte Zeichenfolge in Anführungszeichen setzen müssen, damit Sie die Erweiterung direkt während der Variablenzuweisung durchführen können:Sie können die Erweiterung auch in der
echo
Befehlszeile ausführen, solange dies vor der Parametererweiterung möglich ist:Wenn Sie aus irgendeinem Grund die Tilde für die
$x
Variable ohne Erweiterung wirklich beeinflussen müssen und sie beimecho
Befehl erweitern können, müssen Sie zweimal fortfahren, um zwei Erweiterungen der$x
Variablen zu erzwingen :Beachten Sie jedoch, dass je nach Kontext, in dem Sie eine solche Struktur verwenden, unerwünschte Nebenwirkungen auftreten können. Als Faustregel sollten Sie lieber alles vermeiden, was Sie benötigen,
eval
wenn Sie einen anderen Weg haben.Wenn Sie das Tilde-Problem im Gegensatz zu anderen Erweiterungen gezielt angehen möchten, ist eine solche Struktur sicherer und portabler:
Diese Struktur überprüft explizit das Vorhandensein eines Leading
~
und ersetzt es durch das Home-Verzeichnis des Benutzers, wenn es gefunden wird.Nach Ihrem Kommentar
x="${HOME}/${x#"~/"}"
mag dies in der Tat für jemanden überraschend sein, der nicht in der Shell-Programmierung verwendet wird, aber tatsächlich mit derselben POSIX-Regel verknüpft ist, die ich oben zitiert habe.Gemäß dem POSIX-Standard erfolgt die Entfernung von Anführungszeichen zuletzt und die Parametererweiterung sehr früh. Somit
${#"~"}
wird weit vor der Auswertung der äußeren Anführungszeichen ausgewertet und erweitert. Abwechselnd wie in den Parametererweiterungsregeln definiert:Daher muss die rechte Seite des
#
Bedieners korrekt zitiert oder ausgeblendet werden, um eine Tilde-Expansion zu vermeiden.Um es anders
x="${HOME}/${x#"~/"}"
auszudrücken: Wenn der Shell-Interpret es betrachtet , sieht er:${HOME}
und${x#"~/"}
muss erweitert werden.${HOME}
wird auf den Inhalt der$HOME
Variablen erweitert.${x#"~/"}
löst eine verschachtelte Erweiterung aus:"~/"
wird analysiert, aber in Anführungszeichen als Literal 1 behandelt . Sie hätten hier einfache Anführungszeichen mit demselben Ergebnis verwenden können.${x#"~/"}
Der Ausdruck selbst wird jetzt erweitert, wodurch das Präfix~/
aus dem Wert von entfernt wird$x
.${HOME}
, das Literal/
, die Erweiterung${x#"~/"}
.a=$b
finde ich es normalerweise klarer, doppelte Anführungszeichen hinzuzufügen.Übrigens, wenn Sie sich die
case
Syntax genauer ansehen , werden Sie die"~/"*
Konstruktion sehen, die auf dem gleichen Konzept beruht, dasx=~/'someDirectory'
ich oben erklärt habe (auch hier könnten doppelte und einfache Anführungszeichen austauschbar verwendet werden).Machen Sie sich keine Sorgen, wenn diese Dinge auf den ersten Blick dunkel erscheinen (vielleicht sogar auf den zweiten oder späteren Blick!). Meiner Meinung nach ist die Parametererweiterung mit Subshells eines der komplexesten Konzepte, die beim Programmieren in Shell-Sprache zu verstehen sind.
Ich weiß, dass einige Leute heftig anderer Meinung sein mögen, aber wenn Sie die Shell-Programmierung genauer lernen möchten, empfehle ich Ihnen, das Advanced Bash Scripting Guide zu lesen : Es lehrt Bash-Scripting, also mit vielen Erweiterungen und Bells-and- pfeift im Vergleich zu POSIX-Shell-Skripten, aber ich fand es gut geschrieben mit vielen praktischen Beispielen. Sobald Sie dies geschafft haben, können Sie sich bei Bedarf leicht auf POSIX-Funktionen beschränken. Ich persönlich denke, dass der direkte Einstieg in den POSIX-Bereich für Anfänger eine unnötig steile Lernkurve darstellt (vergleichen Sie meinen POSIX-Tilde-Ersatz mit @ m0dulars regulärem Bash äquivalent, um eine Vorstellung davon zu bekommen, was ich meine;)!).
1 : Was mich dazu bringt, einen Fehler in Dash zu finden, der die Tilde-Erweiterung hier nicht korrekt implementiert (überprüfbar mit
x='~/foo'; echo "${x#~/}"
). Die Parametererweiterung ist sowohl für den Benutzer als auch für die Shell-Entwickler selbst ein komplexes Feld!quelle
x="${HOME}/${x#"~/"}"
? Es sieht aus wie eine Verkettung von drei Strings:"${HOME}/${x#"
,~/
, und"}"
. Ermöglicht die Shell verschachtelte doppelte Anführungszeichen, wenn sich das innere Paar doppelter Anführungszeichen in einem${ }
Block befindet?Eine mögliche Antwort:
Da Sie Eingaben aus einer Datei lesen, würde ich dies nicht tun.
Sie können das ~ wie folgt suchen und durch den Wert von $ HOME ersetzen:
Gibt mir:
quelle
${parameter/pattern/string}
Erweiterung eine Bash-Erweiterung ist und möglicherweise nicht in anderen Shells verfügbar ist.case
Struktur gut zeigt, wie benutzerfreundlicher Bash-Skripte besonders sind für Anfänger.