Oder allgemeiner: Wie entferne ich ein Element aus einer durch Doppelpunkte getrennten Liste in einer Bash-Umgebungsvariablen?
Ich dachte, ich hätte vor Jahren einen einfachen Weg gesehen, dies mit den fortgeschritteneren Formen der Bash-Variablenerweiterung zu tun, aber wenn ja, habe ich den Überblick verloren. Eine schnelle Suche bei Google ergab überraschend wenige relevante Ergebnisse und keine, die ich als "einfach" oder "elegant" bezeichnen würde. Zum Beispiel zwei Methoden mit sed bzw. awk:
PATH=$(echo $PATH | sed -e 's;:\?/home/user/bin;;' -e 's;/home/user/bin:\?;;')
PATH=!(awk -F: '{for(i=1;i<=NF;i++){if(!($i in a)){a[$i];printf s$i;s=":"}}}'<<<$PATH)
Gibt es nichts Unkompliziertes? Gibt es etwas Analoges zu einer split () - Funktion in Bash?
Update:
Es sieht so aus, als müsste ich mich für meine absichtlich vage Frage entschuldigen. Ich war weniger daran interessiert, einen bestimmten Anwendungsfall zu lösen, als eine gute Diskussion anzuregen. Zum Glück habe ich es verstanden!
Hier gibt es einige sehr clevere Techniken. Am Ende habe ich meiner Toolbox die folgenden drei Funktionen hinzugefügt. Die Magie geschieht in path_remove, das weitgehend auf Martin Yorks kluger Verwendung der awk
RS-Variablen basiert .
path_append () { path_remove $1; export PATH="$PATH:$1"; }
path_prepend () { path_remove $1; export PATH="$1:$PATH"; }
path_remove () { export PATH=`echo -n $PATH | awk -v RS=: -v ORS=: '$0 != "'$1'"' | sed 's/:$//'`; }
Die einzige echte Kruft darin ist die Verwendung sed
, um den hinteren Doppelpunkt zu entfernen. Wenn man bedenkt, wie einfach der Rest von Martins Lösung ist, bin ich durchaus bereit, damit zu leben!
Verwandte Frage: Wie manipuliere ich $ PATH-Elemente in Shell-Skripten?
quelle
WORK=`echo -n ${1} | awk -v RS=: -v ORS=: '$0 != "'${3}'"' | sed 's/:$//'`; eval "export ${2}=${WORK}"
aber Sie müssen es nennenfunc $VAR VAR pattern
(basierend auf @ martin-york und @ andrew-aylett)Antworten:
Eine Minute mit awk:
Bearbeiten: Es Antwort auf Kommentare unten:
Als Antwort auf ein Sicherheitsproblem bearbeiten: (das ist für die Frage nicht relevant)
Dadurch werden alle nachfolgenden Doppelpunkte entfernt, die durch Löschen der letzten Einträge übrig bleiben. Dies würde
.
Ihren Pfad effektiv erweitern .quelle
PATH
Variable tut , als eine spezielle Regel bezeichnet aktuelles Verzeichnis in alle Unix - Shells seit mindestens V7 Unix 1979 Es ist immer noch in tutbash
. Überprüfen Sie das Handbuch oder versuchen Sie es selbst.Mein dreckiger Hack:
quelle
Da das große Problem bei der Substitution die Endfälle sind, können Sie die Endfälle nicht von den anderen Fällen unterscheiden. Wenn der Pfad am Anfang und am Ende bereits Doppelpunkte hatte, könnten wir einfach nach unserer gewünschten Zeichenfolge suchen, die mit Doppelpunkten umwickelt ist. So wie es ist, können wir diese Doppelpunkte einfach hinzufügen und anschließend entfernen.
Pure Bash :).
quelle
WORK
undPATH
da die Variablenerweiterung erfolgt, nachdem die Zeile für die Variablenzuweisung und die Befehlsausführung in Abschnitte analysiert wurde.REMOVE
Möglicherweise muss ein Anführungszeichen angegeben werden, oder Sie können Ihre Zeichenfolge direkt in den Ersatz einfügen, wenn es sich um eine Konstante handelt.Hier ist die einfachste Lösung, die ich finden kann:
Im obigen Beispiel wird jedes Element in $ PATH entfernt, das "usr" enthält. Sie können "* usr *" durch "/ home / user / bin" ersetzen, um nur dieses Element zu entfernen.
Update pro Sschuberth
Obwohl ich denke, dass Leerzeichen in a
$PATH
eine schreckliche Idee sind, ist hier eine Lösung, die damit umgeht:oder
quelle
Hier ist ein Einzeiler, der trotz der aktuell akzeptierten und am höchsten bewerteten Antworten keine unsichtbaren Zeichen zu PATH hinzufügt und mit Pfaden umgehen kann, die Leerzeichen enthalten:
Persönlich finde ich das auch leicht zu lesen / verstehen, und es beinhaltet nur allgemeine Befehle, anstatt awk zu verwenden.
quelle
export PATH=$(p=$(echo $PATH | tr ":" "\0" | grep -v -z "/cygwin/" | tr "\0" ":"); echo ${p%:})
(obwohl Sie sich vielleicht fragen möchten, warum Sie das brauchen, wenn Sie dies tun :))grep -v "^/path/to/remove\$"
odergrep -v -x "/path/to/remove"
tr
ist häufiger alsawk
? ;)tr
eher über ein einfaches Tool als über einen Interpreterawk
.echo "..."
mitprintf "%s" "..."
für sie auf Wegen wie zu arbeiten-e
und ähnliche. Siehe stackoverflow.com/a/49418406/102441Hier ist eine Lösung, die:
IFS
,Entfernt alle Vorkommen des Arguments in
PATH
.quelle
Habe es aus meiner .bashrc-Datei ausgegraben. Wenn Sie mit PATH herumspielen und es verloren geht, ist awk / sed / grep nicht mehr verfügbar :-)
quelle
Die beste reine Bash-Option, die ich bisher gefunden habe, ist die folgende:
Dies basiert auf der nicht ganz korrekten Antwort auf Verzeichnis zu $ PATH hinzufügen, falls es nicht bereits in Superuser vorhanden ist.
quelle
removePath () { PATH=${PATH/":$1"/}; PATH=${PATH/"$1:"/}; }
$PATH
einen Unterordner des Zielpfads enthält (dh gelöscht werden soll). Zum Beispiel:a:abc/def/bin:b
->a/bin:b
, wannabc/def
soll gelöscht werden.Ich habe gerade die Funktionen in der Bash-Distribution verwendet, die anscheinend seit 1991 vorhanden sind. Diese befinden sich immer noch im Bash-Docs-Paket auf Fedora und wurden früher verwendet
/etc/profile
, aber nicht mehr ...quelle
Ich habe dazu eine Antwort schreiben hier (mit awk auch). Aber ich bin mir nicht sicher, ob Sie danach suchen? Zumindest scheint mir klar zu sein, was es tut, anstatt zu versuchen, in eine Zeile zu passen. Für einen einfachen Einzeiler, der nur Sachen entfernt, empfehle ich
Ersetzen ist
oder (kürzer aber weniger lesbar)
Wie auch immer, für dieselbe Frage und viele nützliche Antworten siehe hier .
quelle
awk '$0 !~ "/bin"'
. Dh mit dem awk-Operator Zeilen behalten, die nicht '/ bin' enthalten!~
.Nun, in Bash, da es den regulären Ausdruck unterstützt, würde ich einfach tun:
quelle
Ich mag die drei Funktionen, die in @ BenBlanks Update zu seiner ursprünglichen Frage gezeigt werden. Um sie zu verallgemeinern, verwende ich ein Formular mit zwei Argumenten, mit dem ich PATH oder eine andere gewünschte Umgebungsvariable festlegen kann:
Anwendungsbeispiele:
Beachten Sie, dass ich auch einige Anführungszeichen hinzugefügt habe, um die ordnungsgemäße Verarbeitung von Pfadnamen zu ermöglichen, die Leerzeichen enthalten.
quelle
Was ist eleganter als awk?
Python! Es ist eine besser lesbare und wartbare Lösung, und es ist leicht zu überprüfen, ob es wirklich das tut, was Sie wollen.
Angenommen, Sie möchten das erste Pfadelement entfernen?
(Anstatt von zu leiten
echo
,os.getenv['PATH']
wäre es etwas kürzer und würde das gleiche Ergebnis wie oben liefern, aber ich mache mir Sorgen, dass Python etwas mit dieser Umgebungsvariablen machen könnte, daher ist es wahrscheinlich am besten, es direkt von der Umgebung zu leiten, die Sie interessiert .)Ähnlich vom Ende zu entfernen:
Um diese wiederverwendbaren Shell-Funktionen zu erstellen, die Sie beispielsweise in Ihre .bashrc-Datei einfügen können:
quelle
Ja, wenn Sie beispielsweise einen Doppelpunkt am Ende von PATH einfügen, wird das Entfernen eines Pfads weniger umständlich und fehleranfällig.
quelle
Wenn Sie Bedenken haben, Duplikate in $ PATH zu entfernen , ist es meiner Meinung nach am elegantesten, sie gar nicht erst hinzuzufügen. In 1 Zeile:
Der Ordner $ kann durch irgendetwas ersetzt werden und Leerzeichen enthalten ("/ home / user / my documents").
quelle
Die eleganteste reine Bash-Lösung, die ich bisher gefunden habe:
quelle
Die meisten anderen vorgeschlagenen Lösungen beruhen nur auf String - Matching und sie berücksichtigen nicht die Pfadsegmente mit speziellen Namen wie
.
,..
oder~
. Die folgende Bash-Funktion löst Verzeichniszeichenfolgen in ihrem Argument und in Pfadsegmenten auf, um logische Verzeichnisübereinstimmungen sowie Zeichenfolgenübereinstimmungen zu finden.Prüfung:
quelle
Linux from Scratch definiert drei Bash-Funktionen in
/etc/profile
:Ref: http://www.linuxfromscratch.org/blfs/view/svn/postlfs/profile.html
quelle
Ich weiß, dass diese Frage nach BASH fragt, was jeder bevorzugen sollte, aber da ich Symmetrie mag und manchmal "csh" verwenden muss, habe ich das Äquivalent zu "path_prepend ()", "path_append ()" und "path_remove" erstellt () "elegante Lösung oben.
Das Wesentliche ist, dass "csh" keine Funktionen hat, also habe ich kleine Shell-Skripte in mein persönliches bin-Verzeichnis gestellt, die sich wie die Funktionen verhalten. Ich erstelle Aliase, um diese Skripte zu SOURCE, um die Änderungen der angegebenen Umgebungsvariablen vorzunehmen.
~ / bin / _path_remove.csh:
~ / bin / _path_append.csh:
~ / bin / _path_prepend.csh:
~ / bin / .cshrc:
Sie können sie so verwenden ...
quelle
Da dies in der Regel recht problematisch ist, da es KEINE elegante Art gibt, empfehle ich, das Problem zu vermeiden, indem Sie die Lösung neu anordnen: Bauen Sie Ihren Pfad auf, anstatt zu versuchen, ihn abzureißen.
Ich könnte genauer sein, wenn ich Ihren wirklichen Problemkontext kennen würde. In der Zwischenzeit werde ich einen Software-Build als Kontext verwenden.
Ein häufiges Problem bei Software-Builds besteht darin, dass es auf einigen Computern nicht funktioniert, was letztendlich darauf zurückzuführen ist, wie jemand seine Standard-Shell (PATH und andere Umgebungsvariablen) konfiguriert hat. Die elegante Lösung besteht darin, Ihre Build-Skripte durch vollständige Angabe der Shell-Umgebung immun zu machen. Codieren Sie Ihre Build-Skripte, um den PATH und andere Umgebungsvariablen basierend auf den von Ihnen gesteuerten Assemblierungselementen festzulegen, z. B. den Speicherort des Compilers, der Bibliotheken, Tools, Komponenten usw. Machen Sie jedes konfigurierbare Element zu etwas, das Sie einzeln festlegen, überprüfen und überprüfen können Verwenden Sie dann entsprechend in Ihrem Skript.
Zum Beispiel habe ich einen Maven-basierten WebLogic-bezogenen Java-Build, den ich bei meinem neuen Arbeitgeber geerbt habe. Das Build-Skript ist bekannt dafür, dass es zerbrechlich ist, und ein anderer neuer Mitarbeiter und ich haben drei Wochen (nicht Vollzeit, nur hier und da, aber immer noch viele Stunden) damit verbracht, es auf unseren Maschinen zum Laufen zu bringen. Ein wesentlicher Schritt war, dass ich die Kontrolle über den PATH übernahm, damit ich genau wusste, welches Java, welcher Maven und welches WebLogic aufgerufen wurde. Ich habe Umgebungsvariablen erstellt, um auf jedes dieser Tools zu verweisen, und dann den PATH basierend auf diesen und einigen anderen berechnet. Ähnliche Techniken zähmten die anderen konfigurierbaren Einstellungen, bis wir schließlich einen reproduzierbaren Build erstellten.
Verwenden Sie Maven übrigens nicht, Java ist in Ordnung und kaufen Sie WebLogic nur, wenn Sie das Clustering unbedingt benötigen (aber ansonsten nein, und insbesondere nicht die proprietären Funktionen).
Die besten Wünsche.
quelle
PATH
. Sicher, Sie könnten Ihre eigenen bauen, aber jedes Mal, wenn Ihr Administrator etwas bewegt, müssen Sie herausfinden, wo er es abgelegt hat. Diese Art der Niederlage hat den Zweck, einen Administrator zu haben.Wie bei @litb habe ich eine Antwort auf die Frage " Wie manipuliere ich $ PATH-Elemente in Shell-Skripten " beigesteuert, sodass meine Hauptantwort dort ist.
Die "Split" -Funktionalität in
bash
und anderen Bourne-Shell-Derivaten wird am besten mit$IFS
dem Inter-Field-Separator erreicht. Zum Beispiel wird die Positions Argumente zu setzen ($1
,$2
, ...) zu den Elementen der PATH, zu verwenden:Es wird in Ordnung funktionieren, solange in $ PATH keine Leerzeichen vorhanden sind. Es ist nicht trivial, es für Pfadelemente mit Leerzeichen zum Laufen zu bringen - es bleibt dem interessierten Leser überlassen. Es ist wahrscheinlich einfacher, mit einer Skriptsprache wie Perl damit umzugehen.
Ich habe auch ein Skript,
clnpath
das ich ausgiebig zum Einstellen meines Pfads verwende. Ich habe es in der Antwort auf " Wie man verhindert, dass PATH-Variablen in csh dupliziert werden " dokumentiert .quelle
Was dieses Problem ärgerlich macht, sind die Zaunpfostenfälle zwischen dem ersten und dem letzten Element. Das Problem kann elegant gelöst werden, indem IFS geändert und ein Array verwendet wird, aber ich weiß nicht, wie der Doppelpunkt wieder eingeführt werden soll, sobald der Pfad in die Array-Form konvertiert wurde.
Hier ist eine etwas weniger elegante Version, die ein Verzeichnis von der
$PATH
Verwendung nur der Zeichenfolgenmanipulation entfernt. Ich habe es getestet.quelle
Hier ist ein Perl-Einzeiler:
Die
$a
Variable erhält den zu entfernenden Pfad. Die Befehles
(Ersatz) undprint
Befehle wirken sich implizit auf die$_
Variable aus.quelle
Gutes Zeug hier. Ich benutze dieses, um überhaupt keine Dupes hinzuzufügen.
quelle
case ":$PATH:" in (*:"$nodup":*) ;; (*) PATH="$PATH:$nodup" ;; esac
Bei aktiviertem Extended Globbing ist Folgendes möglich:
quelle
Erweiterter Globbing-Einzeiler (na ja, irgendwie):
Es scheint nicht nötig zu sein, Schrägstrichen in Höhe von 1 USD zu entkommen.
quelle
Durch Hinzufügen von Doppelpunkten zu PATH können wir auch Folgendes tun:
quelle
In path_remove_all (per Proxy):
quelle
Obwohl dies ein sehr alter Thread ist, dachte ich, dass diese Lösung von Interesse sein könnte:
fand es in diesem Blog-Beitrag . Ich denke, ich mag dieses am meisten :)
quelle
Ich habe einen etwas anderen Ansatz gewählt als die meisten Leute hier und mich speziell auf die Manipulation von Saiten konzentriert, wie zum Beispiel:
Das Obige ist ein vereinfachtes Beispiel für die endgültigen Funktionen, die ich verwende. Ich habe auch einen Pfad vor / nach einem angegebenen Pfad erstellt
path_add_before
und zugelassenpath_add_after
, der bereits in PATH enthalten ist.Der vollständige Funktionsumfang ist in path_helpers.sh in meinen Punktedateien verfügbar . Sie unterstützen das Entfernen / Anhängen / Voranstellen / Einfügen am Anfang / Mitte / Ende der PATH-Zeichenfolge vollständig.
quelle