Usuwanie katalogu ze ŚCIEŻKI

28

Próbuję skompilować wxWidgets przy użyciu MingW i mam cygwina na mojej ścieżce, co wydaje się być w konflikcie. Chciałbym więc usunąć /d/Programme/cygwin/binze zmiennej PATH i zastanawiam się, czy istnieje jakiś elegancki sposób na zrobienie tego.

Naiwnym podejściem byłoby echo do pliku, usunięcie go ręcznie i źródło, ale założę się, że jest lepsze podejście do tego.

Devolus
źródło
2
Wymieniono tutaj wiele technik: stackoverflow.com/questions/370047/…
slm

Odpowiedzi:

23

Nie ma standardowych narzędzi do „edycji” wartości $ PATH (tzn. „Dodaj folder tylko wtedy, gdy jeszcze nie istnieje” lub „usuń ten folder”). Po prostu wykonujesz:

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

tak byłoby w przypadku bieżącej sesji, jeśli chcesz zmienić na stałe, dodaj ją do dowolnego profilu .bashrc, bash.bashrc, / etc / - niezależnie od potrzeb systemu i użytkownika. Jeśli jednak używasz BASH, możesz również wykonać następujące czynności, jeśli, powiedzmy, chcesz usunąć katalog /home/wrong/dir/ze zmiennej PATH, zakładając, że jest on na końcu:

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

Więc w twoim przypadku możesz użyć

PATH=$(echo "$PATH" | sed -e 's/:\/d\/Programme\/cygwin\/bin$//')
tusharmakkar08
źródło
1
Jeśli dana ścieżka znajduje się na początku zmiennej PATH, musisz dopasować dwukropek na końcu. Jest to denerwujące zastrzeżenie, które komplikuje łatwe ogólne operacje na zmiennych PATH.
Graeme
4
Kiedy mam do czynienia z tyloma ukośnikami, wolę zmienić ogranicznik wyrażenia regularnego na /coś takiego |: PATH=$(echo "$PATH" | sed -e 's|:/d/Programme/cygwin/bin$||')aby zapobiec ucieczce.
Matthias Kuhn
17

W bash:

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

Jeśli nie używasz zmiennej pośredniej, musisz zabezpieczyć /znaki w katalogu, aby usunąć, aby nie były traktowane jako koniec wyszukiwanego tekstu.

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

Pierwsza i trzecia linia są ustawione tak, aby każdy komponent ścieżki wyszukiwania był otoczony :, aby uniknąć specjalnego umieszczenia pierwszego i ostatniego komponentu. Drugi wiersz usuwa określony komponent.

Gilles „SO- przestań być zły”
źródło
Dzięki @Gilles, twoja odpowiedź skłoniła mnie do wymyślenia własnego rozwiązania , które wymaga tylko trzech manipulacji PATH zamiast czterech. * 8 ')
Mark Booth
8

Po rozważeniu innych przedstawionych tutaj opcji i niezrozumieniu, jak niektóre z nich działały, opracowałem własną path_removefunkcję, którą dodałem do mojej .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
}

Skończyło się to dość blisko rozwiązania Gillesa, ale zostało zamknięte jako funkcja bash, której można łatwo użyć w wierszu poleceń.

Ma tę zaletę, że jako funkcja bash działa jak program bez konieczności bycia programem na ścieżce i nie wymaga uruchamiania żadnych zewnętrznych programów, wystarczy manipulacja ciągiem bash.

Wydaje się dość solidny, w szczególności nie zmienia somepath:mypath/mysubpathsię somepath/mysubpath: jeśli uruchomisz path_remove mypath, co było problemem z moją poprzednią path_removefunkcją.

Doskonałe objaśnienie działania manipulacji ciągiem bash można znaleźć w Advanced Bash-Scripting Guide .

Mark Booth
źródło
6

Tak więc, łącząc odpowiedzi z @ gilles i @ bruno-a (i kilku innych sztuczek sed) wymyśliłem ten jednowierszowy, który usunie (każdy) REMOVE_PART z PATH, niezależnie od tego, czy występuje na początku, środek lub koniec ŚCIEŻKI

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

To trochę nieporęczne, ale fajnie jest móc to zrobić za jednym razem. ;Służy do łączenia ze sobą dwóch oddzielnych sed polecenia:

  • s@:$REMOVE_PART:@:@g(który zastępuje :$REMOVE_PART:jednym :)
  • s@^:\(.*\):\$@\1@ (który usuwa główne i końcowe dwukropki, które dodaliśmy za pomocą polecenia echo)

I w podobny sposób właśnie udało mi się wymyślić ten jeden wiersz do dodawania ADD_PART do ŚCIEŻKI, tylko jeśli ŚCIEŻKA jeszcze go nie zawiera

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')

Zmień ostatnią część na, echo "$PATH:$ADD_PART"jeśli chcesz dodać ADD_PART na końcu ŚCIEŻKI zamiast na początku.

...

... lub aby było to jeszcze łatwiejsze, utwórz skrypt wywoływany remove_path_partz zawartością

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

oraz skrypt wywoływany prepend_path_partz zawartością

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

oraz skrypt wywoływany append_path_partz zawartością

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

uczyń je wszystkimi wykonywalnymi, a następnie wywołać je w następujący sposób:

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

Zgrabnie, nawet jeśli sam tak mówię :-)

Lurchman
źródło
Podoba mi się sugestia, zwłaszcza pomysł ze skryptami.
Devolus,
3

O wiele prostsza jedna wkładka.

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

użytkownik332870
źródło
2

Ciekawym ćwiczeniem jest napisanie funkcji bash w celu usunięcia katalogu ze zmiennej ścieżki.

Oto niektóre funkcje, których używam w moich plikach .bash * do dodawania / dodawania katalogów do ścieżek. Mają one tę zaletę, że usuwają zduplikowane wpisy, jeśli takie istnieją, i działają z dowolnym rodzajem zmiennej oddzielonej dwukropkami (ŚCIEŻKA, MANPATH, INFOPATH, ...). funkcja remove_from usuwa katalog.

# {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\"
}
Greg Tarsa
źródło
2

Poniżej znajduje się poprawiony kod z rozwiązania Grega Tarsy. Używane są tylko wbudowane polecenia bash. W ten sposób zaoszczędzi wiele wywołań systemowych fork ().

# 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
}
Jie Gong
źródło
1

Aby uzupełnić / poprawić akceptowaną odpowiedź od Tushar, możesz:

  • unikaj konieczności ucieczki przed ukośnikami w ścieżce przy użyciu ograniczników nie-ukośników
  • pomiń tę -eopcję, jak na stronie podręcznika sed : „Jeśli nie podano opcji -e, --expression, -f lub --file, pierwszy skrypt nie będący opcją jest traktowany jako skrypt sed do interpretacji.”
  • użyj gflagi (globalnej), aby usunąć wszystkie wystąpienia

W końcu daje coś takiego:

PATH=$(echo "$PATH" | sed 's@:/home/wrong/dir$@@g')
Bruno A.
źródło
0

Obecne odpowiedzi nie rozwiązują mojego podobnego problemu, ponieważ muszę usunąć wiele ścieżek. Wszystkie te ścieżki są podkatalogami jednego katalogu. W takim przypadku ta jedna linijka działa dla mnie: (załóżmy, że wzór polega na cygwinusunięciu wszystkich ścieżek, które zawiera cygwin)

pattern=cygwin; export PATH=$(echo $PATH|tr ':' '\n'|sed "\#${pattern}#d" |tr '\n' ':')
Penghe Geng
źródło