Видалення каталогу з PATH


28

Я намагаюся компілювати wxWidgets за допомогою MingW, і у мене на шляху є cygwin, який, здається, конфліктує. Тому я хотів би видалити /d/Programme/cygwin/binзі змінної PATH, і мені цікаво, чи є якийсь елегантний спосіб це зробити.

Наївним підходом було б повторити його у файлі, видалити його вручну та надсилати джерело, але я вважаю, що для цього краще підійти.


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

1
Якщо відповідний шлях знаходиться на початку змінної PATH, вам потрібно зіставити двокрапку в кінці. Це дратівливий застереження, яке ускладнює прості загальні маніпуляції змінних PATH.
Graeme

4
Маючи справу з такою кількістю косої риси, я вважаю за краще змінити відмінювач регулярних виразів /на щось на кшталт |: PATH=$(echo "$PATH" | sed -e 's|:/d/Programme/cygwin/bin$||')щоб запобігти втечі.
Маттіас Кун

17

В bash:

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, вона працює як програма без необхідності бути програмою на шляху, і їй не потрібні ніякі зовнішні програми для запуску, а лише маніпуляція з рядком.

Виявляється , досить міцним, зокрема , він не включається somepath:mypath/mysubpathв somepath/mysubpath: якщо ви біжите path_remove mypath, що проблема у мене був з моєї попередньої path_removeфункцією.

Відмінне пояснення того, як працює маніпуляція струнними стрибками, можна знайти в Додатковому посібнику з написання сценаріїв .


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)

Акуратно, навіть якщо я сам так скажу :-)


Мені подобається пропозиція, особливо ідея зі сценаріями.
Деволус

3

Набагато простіший один лайнер.

експортувати PATH = `ехо $ PATH | tr ":" "\ n" | grep -v "анаконда" | tr "\ n" ":" `


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

Щоб доповнити / покращити прийняту відповідь від Тушара, ви можете:

  • уникайте необхідності уникати косої частини в PATH, використовуючи нерозрізники
  • пропустіть -eпараметр відповідно до сторінки sed man : "Якщо параметр -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' ':')
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.