Verzeichnis aus PATH entfernen


28

Ich versuche, wxWidgets mit MingW zu kompilieren, und ich habe Cygwin auf meinem Weg, was zu Konflikten zu führen scheint. Ich möchte also /d/Programme/cygwin/binaus der PATH-Variablen entfernen und frage mich, ob es eine elegante Möglichkeit gibt, dies zu tun.

Der naive Ansatz wäre, es in eine Datei umzuwandeln, sie manuell zu entfernen und als Quelle zu verwenden, aber ich wette, es gibt einen besseren Ansatz dafür.


2
Viele Techniken sind hier aufgelistet: stackoverflow.com/questions/370047/…
slm

Antworten:


23

Es gibt keine Standardwerkzeuge, um den Wert von $ PATH zu "bearbeiten" (dh "Ordner nur hinzufügen, wenn er noch nicht existiert" oder "Diesen Ordner entfernen"). Sie führen gerade aus:

export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games

Dies gilt für die aktuelle Sitzung, wenn Sie sie dauerhaft ändern möchten und sie zu einer beliebigen .bashrc-, bash.bashrc- oder / etc / -Profildatei hinzufügen möchten. Wenn Sie jedoch BASH verwenden, können Sie auch Folgendes tun, wenn Sie beispielsweise das Verzeichnis /home/wrong/dir/aus Ihrer PATH-Variablen entfernen möchten , vorausgesetzt, es befindet sich am Ende:

PATH=$(echo "$PATH" | sed -e 's/:\/home\/wrong\/dir$//')

Also in deinem Fall darfst du verwenden

PATH=$(echo "$PATH" | sed -e 's/:\/d\/Programme\/cygwin\/bin$//')

1
Befindet sich der betreffende Pfad am Anfang der PATH-Variablen, müssen Sie den Doppelpunkt am Ende angeben. Dies ist eine nervige Einschränkung, die die einfache generische Manipulation von PATH-Variablen erschwert.
Graeme

4
Bei so vielen Schrägstrichen ziehe ich es vor, das Regex-Trennzeichen /durch Folgendes zu ersetzen |: um PATH=$(echo "$PATH" | sed -e 's|:/d/Programme/cygwin/bin$||')zu verhindern, dass alles entweicht.
Matthias Kuhn

17

In der Bash:

directory_to_remove=/d/Programme/cygwin/bin
PATH=:$PATH:
PATH=${PATH//:$directory_to_remove:/:}
PATH=${PATH#:}; PATH=${PATH%:}

Wenn Sie keine Zwischenvariable verwenden, müssen Sie /die zu entfernenden Zeichen im Verzeichnis schützen , damit sie nicht als Ende des Suchtextes behandelt werden.

PATH=:$PATH:
PATH=${PATH//:\/d\/Programme\/cygwin\/bin:/:}
PATH=${PATH#:}; PATH=${PATH%:}

Die erste und die dritte Zeile sind dafür vorgesehen, dass jede Komponente des Suchpfads von :einer speziellen Umhüllung der ersten und der letzten Komponente umgeben wird. Die zweite Zeile entfernt die angegebene Komponente.


Vielen Dank, @Gilles, Ihre Antwort hat mich dazu veranlasst, eine eigene Lösung zu finden , die nur drei Manipulationen von PATH anstelle von vier erfordert. * 8 ')
Mark Booth

8

Nachdem ich andere hier vorgestellte Optionen in Betracht gezogen und nicht vollständig verstanden hatte, wie einige von ihnen funktionierten, entwickelte ich meine eigene path_removeFunktion, die ich zu meiner hinzufügte .bashrc:

function path_remove {
  # Delete path by parts so we can never accidentally remove sub paths
  PATH=${PATH//":$1:"/":"} # delete any instances in the middle
  PATH=${PATH/#"$1:"/} # delete any instance at the beginning
  PATH=${PATH/%":$1"/} # delete any instance in the at the end
}

Dies endete ziemlich nahe an Gilles 'Lösung, wurde jedoch als Bash-Funktion zusammengefasst, die einfach in der Befehlszeile verwendet werden konnte.

Es hat den Vorteil, dass es als Bash-Funktion wie ein Programm funktioniert, ohne dass es ein Programm auf dem Pfad sein muss, und dass keine externen Programme ausgeführt werden müssen, sondern lediglich die Manipulation von Bash-Strings.

Es erscheint ziemlich robust, insbesondere verwandelt es sich nicht somepath:mypath/mysubpathin somepath/mysubpath: Wenn Sie ausführen path_remove mypath, was ein Problem war, das ich mit meiner vorherigen path_removeFunktion hatte.

Eine hervorragende Erklärung für die Funktionsweise der Bash-Manipulation finden Sie im Advanced Bash-Scripting Guide .


6

Aus den Antworten von @gilles und @ bruno-a (und ein paar anderen Sed-Tricks) habe ich diesen Einzeiler entwickelt, der (jeden) REMOVE_PART aus PATH entfernt, unabhängig davon, ob er zu Beginn auftritt. Mitte oder Ende von PATH

PATH=$(REMOVE_PART="/d/Programme/cygwin/bin" sh -c 'echo ":$PATH:" | sed "s@:$REMOVE_PART:@:@g;s@^:\(.*\):\$@\1@"')

Es ist ein bisschen unhandlich, aber es ist schön, es mit einem Schlag schaffen zu können. Mit ;dem werden die beiden getrennten sed-Befehle zusammengefügt:

  • s@:$REMOVE_PART:@:@g(die :$REMOVE_PART:mit einem einzigen ersetzt :)
  • s@^:\(.*\):\$@\1@ (Dies entfernt die führenden und nachfolgenden Doppelpunkte, die wir mit dem Befehl echo hinzugefügt haben.)

In ähnlicher Weise habe ich es gerade geschafft, diesen Einzeiler für das Hinzufügen eines ADD_PART zum PATH zu entwickeln, nur wenn der PATH ihn noch nicht enthält

PATH=$(ADD_PART="/d/Programme/cygwin/bin" sh -c 'if echo ":$PATH:" | grep -q ":$ADD_PART:"; then echo "$PATH"; else echo "$ADD_PART:$PATH"; fi')

Ändern Sie den letzten Teil in, echo "$PATH:$ADD_PART"wenn Sie ADD_PART am Ende von PATH anstatt am Anfang hinzufügen möchten.

...

... oder um dies noch einfacher zu machen, erstellen Sie ein Skript, das remove_path_partmit den Inhalten aufgerufen wird

echo ":$PATH:" | sed "s@:$1:@:@g;s@^:\(.*\):\$@\1@"

und ein Skript prepend_path_partmit dem Inhalt aufgerufen

if echo ":$PATH:" | grep -q ":$1:"; then echo "$PATH"; else echo "$1:$PATH"; fi

und ein Skript append_path_partmit dem Inhalt aufgerufen

if echo ":$PATH:" | grep -q ":$1:"; then echo "$PATH"; else echo "$PATH:$1"; fi

mache sie alle ausführbar und rufe sie dann wie folgt auf:

  • PATH=$(remove_path_part /d/Programme/cygwin/bin)
  • PATH=$(prepend_path_part /d/Programme/cygwin/bin)
  • PATH=$(append_path_part /d/Programme/cygwin/bin)

Ordentlich, auch wenn ich es selbst sage :-)


Mir gefällt der Vorschlag, besonders die Idee mit den Skripten.
Devolus

3

Viel einfacher ein Liner.

export PATH = `echo $ PATH | tr ":" \ n "| grep -v "anaconda" | tr "\ n" ":" `


2

Es ist eine interessante Übung, eine Bash-Funktion zu schreiben, um ein Verzeichnis aus einer Pfadvariablen zu entfernen.

Im Folgenden sind einige Funktionen aufgeführt, die ich in meinen .bash * -Dateien verwende, um Verzeichnisse an Pfade anzuhängen bzw. ihnen voranzustellen. Sie haben die Eigenschaft, doppelte Einträge zu entfernen und mit jeder Art von durch Doppelpunkte getrennten Pfadvariablen (PATH, MANPATH, INFOPATH, ...) zu arbeiten. Die Funktion remove_from entfernt das Verzeichnis.

# {app,pre}pend_to path-var-name dirpath
# remove_from path-var-name dirpath
#
# Functions to manipulate a path-style variable.  {app,pre}pend_to
# both remove any other instances of dirname before adding it to
# the start or end of the path-var-name variable.
#
# Calling example:
#   append_to PATH "/usr/local/bin"
#
# Uses eval to allow target path varname to be passed in.
function remove_from() {
  # add surrounging colons
  eval tmp_path=":\$${1}:"
  # if dir is already there, remove it
  (echo "${tmp_path}" | grep --silent ":${2}:") &&
    tmp_path=`echo "$tmp_path" | sed "s=:${2}:=:=g"`
  # remove surrounding colons
  tmp_path=`echo "$tmp_path" | sed 's=^:==; s=:$=='`
  eval export $1=\"$tmp_path\"
}
function append_to() {
  remove_from "$1" "$2"  # clean the path contents
  eval export $1=\"\$${1}:$2\"
}
function prepend_to() {
  remove_from "$1" "$2"  # clean the path contents
  eval export $1=\"${2}:\$$1\"
}

2

Unten finden Sie überarbeiteten Code aus Greg Tarsas Lösung. Hier werden nur Bash-Befehle verwendet. Auf diese Weise werden viele Systemaufrufe für fork () gespart.

# Calling example:
#   append_to PATH "/usr/local/bin"

function remove_from()
{
    local path="${1}"
    local dir="${2}"
    local -a dirs=()
    local old_ifs="${IFS}"
    IFS=":"
    set -- ${!path}
    while [ "$#" -gt "0" ]
    do
        [ "${1}" != "${dir}" ] && dirs+=("${1}")
        shift
        done
    eval "export ${path}=\"${dirs[*]}\""
    IFS="${old_ifs}"
}

function append_to()
{
    remove_from "${1}" "${2}"
    [ -d "${2}" ] || return
    if [ -n "${!1}" ]
    then
        eval "export ${1}=\"${!1}:${2}\""
    else
        eval "export ${1}=\"${2}\""
    fi
}

function prepend_to()
{
    remove_from "${1}" "${2}"
    [ -d "${2}" ] || return
    if [ -n "${!1}" ]
    then
        eval "export ${1}=\"${2}:${!1}\""
    else
        eval "export ${1}=\"${2}\""
    fi
}

1

Um die akzeptierte Antwort von Tushar zu vervollständigen / zu verbessern, können Sie:

  • Vermeiden Sie es, die Schrägstriche im PATH zu überschreiben, indem Sie Trennzeichen ohne Schrägstriche verwenden
  • Lassen Sie die -eOption gemäß der Manpage sed weg: "Wenn keine Option -e, --expression, -f oder --file angegeben ist, wird das erste Argument, das keine Option ist, als zu interpretierendes sed-Skript verwendet."
  • Verwenden Sie das g(globale) Flag, um alle Vorkommen zu entfernen

Am Ende gibt es so etwas:

PATH=$(echo "$PATH" | sed 's@:/home/wrong/dir$@@g')

0

Die aktuellen Antworten lösen mein ähnliches Problem nicht, da ich mehrere Pfade entfernen muss. Alle diese Pfade sind Unterverzeichnisse eines einzelnen Verzeichnisses. In diesem Fall funktioniert dieser Einzeiler für mich: (Angenommen, das Muster cygwinentfernt alle darin enthaltenen Pfade. cygwin)

pattern=cygwin; export PATH=$(echo $PATH|tr ':' '\n'|sed "\#${pattern}#d" |tr '\n' ':')
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.