Удаление каталога из PATH

28

Я пытаюсь скомпилировать wxWidgets, используя MingW, и на моем пути есть cygwin, который, кажется, конфликтует. Поэтому я хотел бы удалить /d/Programme/cygwin/binиз переменной PATH, и мне интересно, есть ли какой-нибудь элегантный способ сделать это.

Наивным подходом было бы отразить его в файл, удалить его вручную и получить его, но я держу пари, что есть лучший подход к этому.

Devolus
источник
2
Многие методы перечислены здесь: stackoverflow.com/questions/370047/…
slm

Ответы:

23

Нет стандартных инструментов для «редактирования» значения $ PATH (т. Е. «Добавлять папку только тогда, когда она еще не существует» или «удалять эту папку»). Вы просто выполняете:

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

это было бы для текущего сеанса, если вы хотите навсегда изменить его, добавьте его в любой .bashrc, bash.bashrc, / etc / profile - все, что соответствует вашей системе и потребностям пользователя. Однако если вы используете BASH, вы также можете сделать следующее, если, скажем, вы хотите удалить каталог /home/wrong/dir/из переменной PATH, предполагая, что он в конце:

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

Так что в вашем случае вы можете использовать

PATH=$(echo "$PATH" | sed -e 's/:\/d\/Programme\/cygwin\/bin$//')
tusharmakkar08
источник
1
Если рассматриваемый путь находится в начале переменной PATH, вам необходимо сопоставить двоеточие в конце. Это раздражающее предостережение, которое усложняет простые общие манипуляции с переменными PATH.
Грэм,
4
Имея дело с таким количеством слэшей, я предпочитаю менять разделитель регулярных выражений /на что-то вроде |: PATH=$(echo "$PATH" | sed -e 's|:/d/Programme/cygwin/bin$||')чтобы предотвратить все побеги.
Матиас Кун
17

В Баш:

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

Если вы не используете промежуточную переменную, вам нужно защитить /символы в каталоге, чтобы удалить их, чтобы они не рассматривались как конец текста поиска.

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

Первая и третья строка предназначены для размещения каждого компонента пути поиска :, чтобы избежать специального размещения первого и последнего компонента. Вторая строка удаляет указанный компонент.

Жиль "ТАК - перестань быть злым"
источник
Спасибо @Gilles, ваш ответ побудил меня придумать собственное решение , которое требует только трех манипуляций с PATH, а не четырех. * 8 ')
Марк Бут
8

После рассмотрения других вариантов, представленных здесь, и неполного понимания того, как некоторые из них работают, я разработал свою собственную path_removeфункцию, которую я добавил к своей .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
}

Это оказалось довольно близко к решению Жиля, но обернуто как функция bash, которую можно легко использовать в командной строке.

У него есть то преимущество, что, как функция bash, она работает как программа без необходимости быть программой на пути и не требует запуска каких-либо внешних программ, только манипулирование строкой bash.

Он выглядит довольно надежным, в частности, он не превращается somepath:mypath/mysubpathв somepath/mysubpath: если вы запускаете path_remove mypath, это была проблема, с которой я столкнулся в своей предыдущей path_removeфункции.

Отличное объяснение того, как работает bash-строка, можно найти в Расширенном руководстве по Bash-Scripting .

Марк Бут
источник
6

Итак, комбинируя ответы от @gilles и @ bruno-a (и нескольких других уловок sed), я придумал эту однострочную строку, которая удалит (каждый) REMOVE_PART из PATH, независимо от того, происходит ли это в начале, середина или конец пути

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

Это немного громоздко, но приятно иметь возможность сделать это одним ударом. ;Используется для соединения вместе двух отдельных SED команды:

  • s@:$REMOVE_PART:@:@g(который заменяет :$REMOVE_PART:один :)
  • s@^:\(.*\):\$@\1@ (который удаляет начальные и конечные двоеточия, которые мы добавили с помощью команды echo)

И аналогичным образом, мне только что удалось придумать эту строку для добавления ADD_PART в PATH, только если PATH еще не содержит его

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

Измените последнюю часть на, echo "$PATH:$ADD_PART"если вы хотите добавить ADD_PART в конец PATH вместо начала.

...

... или чтобы сделать это еще проще, создайте скрипт remove_path_partс содержимым

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

и скрипт вызывается prepend_path_partс содержимым

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

и скрипт вызывается append_path_partс содержимым

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

сделайте их все исполняемыми, а затем назовите их так:

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

Аккуратно, даже если я сам так скажу :-)

Lurchman
источник
Мне нравится предложение, особенно идея со сценариями.
Деволус
3

Намного проще один вкладыш.

export PATH = `echo $ PATH | tr ":" "\ n" | grep -v "анаконда" | tr "\ n" ":" `

user332870
источник
2

Это интересное упражнение - написать функцию bash для удаления каталога из переменной пути.

Вот некоторые функции, которые я использую в своих файлах .bash * для добавления / добавления каталогов к путям. Они обладают способностью удалять повторяющиеся записи, если таковые имеются, и работают с любыми переменными пути, разделенными двоеточиями (PATH, MANPATH, INFOPATH, ...). функция remove_from удаляет каталог.

# {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

Ниже приведен пересмотренный код решения Грега Тарса. Здесь используются только встроенные команды bash. Таким образом, это сэкономит много системных вызовов 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
}
Цзе Гонг
источник
1

Чтобы завершить / улучшить принятый ответ от Tushar, вы можете:

  • Избегайте экранирования косой черты в переменной PATH с помощью разделителей без косой черты.
  • опустите -eопцию, как указано на странице man sed : «Если не задана опция -e, --expression, -f или --file, то первый интерпретируемый аргумент не является опциональным для интерпретации сценария sed».
  • используйте g(глобальный) флаг, чтобы удалить все вхождения

В конце концов, это дает что-то вроде этого:

PATH=$(echo "$PATH" | sed 's@:/home/wrong/dir$@@g')
Бруно А.
источник
0

Текущие ответы не решают мою похожую проблему в том, что мне нужно удалить несколько путей. Все эти пути являются подкаталогами одного каталога. В этом случае эта однострочная работа работает для меня: (предположим, что шаблон cygwin, т.е. удаляет все пути, которые содержат cygwin)

pattern=cygwin; export PATH=$(echo $PATH|tr ':' '\n'|sed "\#${pattern}#d" |tr '\n' ':')
Пенге Гэн
источник