Удаление каталога от ПУТИ

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

При помощи \x01 (или любой уникальный однобайтовый символ) как временный разделитель полей, записями можно более легко управлять.

join -t$'\x01' <(sed -r 's/.{9}/&\x01/' main) <(cut -b -9 keys) |sed -r 's/(.{9})./\1/'

maxschlepzig's awk пример был быстрее для 45 000 000 записей, но он перестал работать на большем файле. Сколько свободной RAM Вы имеете?

Вот результаты:

45,000,000 unique records, 1,500,000 keys
=========================
awk

real    0m31.971s
user    0m28.782s
sys     0m2.972s

join

real    0m53.733s
user    0m54.255s
sys     0m0.708s

(2x45) 90,000,000 records, 1,500,000 keys
=========================
awk
awk: (FILENAME=main2 FNR=54334297) fatal: assoc_lookup: bucket->ahname_str: can't allocate 11 bytes of memory (Cannot allocate memory)

join

real    1m35.306s
user    1m34.754s
sys     0m1.344s

===================
28
11.01.2014, 23:41
14 ответов

Нет никаких стандартных инструментов, чтобы "отредактировать" значение $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=$(echo "$PATH" | sed -e 's/:\/home\/wrong\/dir$//')

Таким образом в Вашем случае можно использовать

PATH=$(echo "$PATH" | sed -e 's/:\/d\/Programme\/cygwin\/bin$//')
24
27.01.2020, 19:39
  • 1
    Если рассматриваемый путь в начале переменной ПУТИ, необходимо соответствовать двоеточию в конце. Это - раздражающий протест, который усложняет легкие универсальные манипуляции переменными ПУТИ. –  Graeme 11.01.2014, 15:58
  • 2
    При контакте с таким количеством наклонных черт я предпочитаю изменять regex разделитель / с чем-то как |: PATH=$(echo "$PATH" | sed -e 's|:/d/Programme/cygwin/bin$||') предотвратить весь выход. –  Matthias Kuhn 17.03.2016, 14:06

В ударе:

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%:}

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

18
27.01.2020, 19:39

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

  • избегать необходимости избежать косой на пути, используя разделители без косоискателя
  • , опускают опцию -E , как Page PAGE MAN SED : «Если нет -A, --Expression, -f, или вариант, то первый аргумент без опции принимается в виде Sed Script для интерпретации».
  • Используйте флаг G (Global) для удаления всех вхождений

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

PATH=$(echo "$PATH" | sed 's@:/home/wrong/dir$@@g')
1
27.01.2020, 19:39

Итак, объединив ответы @gilles и @bruno-a (и еще пару трюков sed), я придумал этот одиночный лайнер, который удалит (каждый) REMOVE_PART из PATH, независимо от того, происходит ли это в начале, середине или в конце 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)

Neat, even if I say so myself :-)

.
7
27.01.2020, 19:39

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

Вот некоторые функции, которые я использую в моих файлах .bash * для добавления / предложенных каталогов к путям. У них есть достоинство снятия дубликатов записей, если таковые имеются, и работают с любым видом разделяемой толстой кишкой отделенной переменной путь (путь, Manath, 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
27.01.2020, 19:39

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

8
27.01.2020, 19:39

Ниже приведен измененный код решения Грега Тарсы. Здесь используется только сборка 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
}
3
27.01.2020, 19:39

Гораздо проще один лайнер.

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

19
27.01.2020, 19:39

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

pattern=cygwin; export PATH=$(echo $PATH|tr ':' '\n'|sed "\#${pattern}#d" |tr '\n' ':')
0
27.01.2020, 19:39

Этот метод обрабатывает разделитель начального/конечного пути:

echo $PATH | sed 's/:/\n/g' | grep -v <path description> | xargs | tr ' ' ':'

Пояснение:

echoпеременная $PATH в sed, которая заменяет ':' символом новой строки

grepвывод и удаление строк, соответствующих нашему запросу

xargsвывод для замены новых строк пробелами

trвывод для замены пробелов двоеточиями

xargsвыполняет обрезку конечных значений

объединить несколько greps, чтобы удалить несколько путей

7
17.02.2020, 11:48

Можно использовать регулярные выражения Bash для удаления пути из списка.

PATH=:$PATH:
while [[ $PATH = *:$dir_to_remove:* ]]; do
    PATH=${PATH//:$dir_to_remove:/:}
done
# Trim off ":" from the beginning and end.
PATH=${PATH#:}
PATH=${PATH%:}

Техника цикла while также устранит повторяющиеся записи. т.е. При удалении fooиз PATH foo:foo:barна первой итерации цикла while это будет :foo:bar:, а на второй — :bar:, и цикл завершится.

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

Использование только внутренних команд Bash значительно ускорит время выполнения.

Предупреждение:Этот код будет работать, если в ваших каталогах есть специальные символы glob -, но только если вы экранируете их в $dir_to_remove, например.

PATH='/foo:directory *with* stars and [brackets]' # <~ unescaped: fine
dir_to_remove='directory \*with\* stars and \[brackets\]' # <~ must escape
1
14.10.2020, 15:37

fzfи подобные инструменты делают TUI более -удобным для пользователя, чем GUI.

function path_remove {
  local dirs=""
  if dirs="$(fzf --multi <<< "${PATH//:/$'\n'}")"; then
    local path=":$PATH"
    while IFS= read -r line; do
      path="${path/":$line"/}"
    done <<< "$dirs"
    export PATH="${path#:}"
  fi
}
-1
12.09.2021, 21:54

Я использую функции Стивена Коллиера bash _path _, описанные в Linux Journal еще в 2000 году:

https://www.linuxjournal.com/article/3645
https://www.linuxjournal.com/article/3768
https://www.linuxjournal.com/article/3935   

Функция addpathдобавляет запись в путь только в том случае, если ее там изначально нет. delpath -nудаляет из пути все несуществующие -каталоги.

Вы можете получить файл pathfunc.tgzизhttps://web.archive.org/web/20061210054813/http://www.netspinner.co.uk:80/Downloads/pathfunc.tgz

0
13.09.2021, 00:42

Баш Oneliner построен -в:

DIR=/dir/to/remove
PATH=${PATH/${PATH/#$DIR:*/$DIR:}/}${PATH/${PATH/*:$DIR*/:$DIR}/}
  • Использует рекурсивное расширение параметра оболочки для удаления двоеточия до или после удаленного каталога
  • Выкройка состоит из двух половин. Одна половина всегда пуста, другая обеспечивает сокращенный путь.
  • Удаляет только один экземпляр $DIR из $PATH
1
23.11.2021, 18:44

Теги

Похожие вопросы