Ich habe eine Variable in meinem Bash-Skript, deren Wert ungefähr so lautet:
~/a/b/c
Beachten Sie, dass es sich um eine nicht erweiterte Tilde handelt. Wenn ich ls -lt für diese Variable mache (nenne es $ VAR), bekomme ich kein solches Verzeichnis. Ich möchte bash diese Variable interpretieren / erweitern lassen, ohne sie auszuführen. Mit anderen Worten, ich möchte, dass bash eval ausführt, aber den ausgewerteten Befehl nicht ausführt. Ist das in Bash möglich?
Wie habe ich es geschafft, dies ohne Erweiterung in mein Skript zu übertragen? Ich habe das Argument bestanden, indem ich es mit doppelten Anführungszeichen umgeben habe.
Versuchen Sie diesen Befehl, um zu sehen, was ich meine:
ls -lt "~"
Dies ist genau die Situation, in der ich mich befinde. Ich möchte, dass die Tilde erweitert wird. Mit anderen Worten, durch was soll ich Magie ersetzen, um diese beiden Befehle identisch zu machen:
ls -lt ~/abc/def/ghi
und
ls -lt $(magic "~/abc/def/ghi")
Beachten Sie, dass ~ / abc / def / ghi möglicherweise existiert oder nicht.
quelle
eval
.foo=~/"$filepath"
oderfoo="$HOME/$filepath"
dir="$(readlink -f "$dir")"
Antworten:
Aufgrund der Natur von StackOverflow kann ich diese Antwort nicht einfach nicht akzeptieren, aber in den letzten 5 Jahren, seit ich dies gepostet habe, gab es weitaus bessere Antworten als meine zugegebenermaßen rudimentäre und ziemlich schlechte Antwort (ich war jung, töte nicht mich).
Die anderen Lösungen in diesem Thread sind sicherere und bessere Lösungen. Am liebsten würde ich mit einem dieser beiden gehen:
Ursprüngliche Antwort für historische Zwecke (aber bitte nicht verwenden)
Wenn ich mich nicht irre,
"~"
wird es auf diese Weise nicht durch ein Bash-Skript erweitert, da es als Literalzeichenfolge behandelt wird"~"
. Sie können die Erweiterung aufeval
diese Weise erzwingen .Alternativ können Sie auch einfach verwenden,
${HOME}
wenn Sie das Home-Verzeichnis des Benutzers möchten.quelle
${HOME}
Am attraktivsten fand ich . Gibt es einen Grund, dies nicht zu Ihrer primären Empfehlung zu machen? Auf jeden Fall danke!eval
ist ein schrecklicher Vorschlag, es ist wirklich schlimm, dass es so viele positive Stimmen bekommt. Sie werden auf alle möglichen Probleme stoßen, wenn der Wert der Variablen Shell-Metazeichen enthält.Wenn die Variable
var
vom Benutzer eingegeben wird,eval
sollte sie nicht zum Erweitern der Tilde mit verwendet werdenDer Grund ist: Der Benutzer könnte versehentlich (oder absichtlich) tippen, zum Beispiel
var="$(rm -rf $HOME/)"
mit möglichen katastrophalen Folgen.Eine bessere (und sicherere) Möglichkeit ist die Verwendung der Bash-Parametererweiterung:
quelle
#
in"${var/#\~/$HOME}"
?$var
.\~
also Flucht~
? (2) Ihre Antwort geht davon aus, dass dies~
das erste Zeichen in ist$var
. Wie können wir die führenden Leerzeichen in ignorieren$var
?:
in einer nicht zitierten Zeichenfolge. Weitere Informationen in den Dokumenten . Informationen zum Entfernen führender Leerzeichen finden Sie unter Trimmen von Leerzeichen aus einer Bash-Variablen.Ich plagarisiere mich von einer vorherigen Antwort , um dies ohne die Sicherheitsrisiken zu tun, die mit Folgendem verbunden sind
eval
:...benutzt als...
Alternativ ein einfacherer Ansatz, der
eval
sorgfältig verwendet:quelle
printf %q
alles zu entkommen , aber die Tilde, und dann verwenden ,eval
ohne Risiko.Ein sicherer Weg, eval zu verwenden, ist
"$(printf "~/%q" "$dangerous_path")"
. Beachten Sie, dass dies bash-spezifisch ist.Siehe diese Frage für Details
Beachten Sie auch, dass dies unter zsh so einfach wie wäre
echo ${~dangerous_path}
quelle
echo ${~root}
gib mir keine Ausgabe auf zsh (mac os x)export test="~root/a b"; echo ${~test}
Wie wäre es damit:
Oder:
quelle
realpath
Befehl in C kompilieren . Beispielsweise können Sie eine ausführbare Dateirealpath.exe
mit bash und gcc über diese Befehlszeile generieren :gcc -o realpath.exe -x c - <<< $'#include <stdlib.h> \n int main(int c,char**v){char p[9999]; realpath(v[1],p); puts(p);}'
. Prostrealpath ~
->/home/myhome
<workingdir>/~
.Erweitern (kein Wortspiel beabsichtigt) der Antworten von Birryree und Halloleo: Der allgemeine Ansatz ist die Verwendung
eval
, enthält jedoch einige wichtige Einschränkungen, nämlich Leerzeichen und Ausgabeumleitung (>
) in der Variablen. Folgendes scheint für mich zu funktionieren:Versuchen Sie es mit jedem der folgenden Argumente:
Erläuterung
${mypath//>}
Streifen aus>
Zeichen , die eine Datei während des clobber könnteeval
.eval echo ...
ist es, was die eigentliche Tilde-Erweiterung bewirkt-e
Argument dienen zur Unterstützung von Dateinamen mit Leerzeichen.Vielleicht gibt es eine elegantere Lösung, aber das konnte ich mir einfallen lassen.
quelle
$(rm -rf .)
.>
Zeichen enthalten ?Ich glaube, das ist es, wonach du suchst
Anwendungsbeispiel:
quelle
printf %q
es führenden Tildes nicht entgeht - es ist fast verlockend, dies als Fehler einzureichen, da es eine Situation ist, in der es an seinem angegebenen Zweck versagt. In der Zwischenzeit jedoch ein guter Anruf!Hier ist meine Lösung:
quelle
echo
Mittel verlassen, dieexpandTilde -n
sich nicht wie erwartet verhalten, und das Verhalten mit Dateinamen, die Backslashes enthalten, ist von POSIX nicht definiert. Siehe pubs.opengroup.org/onlinepubs/009604599/utilities/echo.htmlEinfach
eval
richtig verwenden: mit Validierung.quelle
printf %q
Dingen sicherer entkommt, als ich darauf vertraue, dass handgeschriebener Validierungscode keine Fehler enthält .printf
ist ein$PATH
'd-Befehl.bash
? Wenn ja,printf
ist ein eingebautes und%q
ist garantiert vorhanden.bash
genug verwendet, um zu wissen, dass ich ihm nicht vertrauen soll. versuchen Sie:x=$(printf \\1); [ -n "$x" ] || echo but its not null!
Hier ist das POSIX-Funktionsäquivalent zu Håkon Hæglands Bash- Antwort
2017-12-10 bearbeiten:
'%s'
per @CharlesDuffy in den Kommentaren hinzufügen .quelle
printf '%s\n' "$tilde_less"
, vielleicht? Andernfalls verhält es sich schlecht, wenn der zu erweiternde Dateiname Backslashes%s
oder eine andere Syntax enthält, die fürprintf
. Davon abgesehen ist dies jedoch eine großartige Antwort - richtig (wenn Bash / Ksh-Erweiterungen nicht abgedeckt werden müssen), offensichtlich sicher (kein Misteval
) und knapp.Warum nicht gleich mit getent in das Home-Verzeichnis des Benutzers eintauchen?
quelle
Nur um die Antwort von birryree für Pfade mit Leerzeichen zu erweitern: Sie können den
eval
Befehl nicht unverändert verwenden , da er die Auswertung nach Leerzeichen trennt. Eine Lösung besteht darin, Leerzeichen für den Befehl eval vorübergehend zu ersetzen:Dieses Beispiel basiert natürlich auf der Annahme, dass
mypath
die Zeichenfolge niemals enthalten ist"_spc_"
.quelle
$(rm -rf .)
Möglicherweise ist dies in Python einfacher.
(1) Über die Unix-Befehlszeile:
Ergebnisse in:
(2) Innerhalb eines Bash-Skripts als einmalig - speichern Sie dies als
test.sh
:Laufende
bash ./test.sh
Ergebnisse in:(3) Als Dienstprogramm - speichern Sie dies als
expanduser
irgendwo auf Ihrem Pfad mit Ausführungsberechtigungen:Dies könnte dann in der Kommandozeile verwendet werden:
Oder in einem Skript:
quelle
echo $thepath
ist fehlerhaft; muss seinecho "$thepath"
, um die weniger seltenen Fälle zu beheben (Namen mit Tabulatoren oder Leerzeichen, die in einzelne Leerzeichen konvertiert werden; Namen mit Globs, die sie erweitert haben), oderprintf '%s\n' "$thepath"
um auch die ungewöhnlichen Fälle zu beheben (dh eine Datei mit dem Namen-n
oder eine Datei mit Backslash-Literale auf einem XSI-kompatiblen System). Ebensothepath=$(expanduser "$1")
echo
ein vollständig implementierungsdefiniertes Verhalten, wenn ein Argument Backslashes enthält. Die optionalen XSI-Erweiterungen für POSIX schreiben standardmäßige (keine-e
oder-E
erforderliche) Erweiterungsverhalten für solche Namen vor.Am einfachsten : Ersetzen Sie "Magie" durch "Eval Echo".
Problem: Sie werden auf Probleme mit anderen Variablen stoßen, weil die Bewertung böse ist. Zum Beispiel:
Beachten Sie, dass das Problem der Injektion bei der ersten Erweiterung nicht auftritt. Also , wenn Sie sind einfach ersetzen
magic
miteval echo
, sollten Sie in Ordnung sein. Wenn Sie dies jedoch tunecho $(eval echo ~)
, ist dies anfällig für Injektionen.Wenn Sie dies
eval echo ~
stattdessen tuneval echo "~"
, würde dies als doppelt erweitert gelten und daher wäre eine Injektion sofort möglich.quelle
s='echo; EVIL_COMMAND'
. (Es wird fehlschlagen, weilEVIL_COMMAND
es auf Ihrem Computer nicht vorhanden ist. Aber wenn dieser Befehlrm -r ~
zum Beispiel gewesen wäre, hätte er Ihr Home-Verzeichnis gelöscht.)Ich habe dies mit variabler Parameterersetzung getan, nachdem ich den Pfad unter anderem mit read -e eingelesen habe. So kann der Benutzer den Pfad auf der Registerkarte vervollständigen, und wenn der Benutzer einen ~ -Pfad eingibt, wird dieser sortiert.
Der zusätzliche Vorteil besteht darin, dass mit der Variablen nichts passiert, wenn keine Tilde vorhanden ist. Wenn eine Tilde vorhanden ist, sich jedoch nicht an der ersten Position befindet, wird sie ebenfalls ignoriert.
(Ich füge das -i zum Lesen ein, da ich es in einer Schleife verwende, damit der Benutzer den Pfad korrigieren kann, wenn ein Problem auftritt.)
quelle