Обратите внимание, что этот метод использует длину ключа фиксированной длины, который начинается на уровне первого байта записи.
При помощи \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
===================
Нет никаких стандартных инструментов, чтобы "отредактировать" значение $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$//')
В ударе:
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%:}
Первая и третья строка там, чтобы принять меры, чтобы каждый компонент пути поиска был окружен :
, избегать специального преобразования регистра первый и последний компонент. Вторая строка удаляет указанный компонент.
Чтобы завершить / улучшить принятый ответ из Tushar, вы можете:
-E
, как Page PAGE MAN SED : «Если нет -A, --Expression, -f, или вариант, то первый аргумент без опции принимается в виде Sed Script для интерпретации». G
(Global) для удаления всех вхождений в конце, он дает что-то вроде этого:
PATH=$(echo "$PATH" | sed 's@:/home/wrong/dir$@@g')
Итак, объединив ответы @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 :-)
.Это интересное упражнение для записи функции 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\"
}
Рассмотрев другие варианты, представленные здесь, и не поняв полностью, как работают некоторые из них, я разработал свою собственную функцию 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 .
Ниже приведен измененный код решения Грега Тарсы. Здесь используется только сборка 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
}
Гораздо проще один лайнер.
export PATH=`echo $PATH | tr ":" "\n" | grep -v "anaconda" | tr "\n" ":"`
Текущие ответы не решают мою аналогичную проблему, поскольку мне нужно удалить несколько путей. Все эти пути являются подкаталогами -одного каталога. В этом случае для меня работает этот один вкладыш -:(, предположим, что шаблон cygwin
, то есть удаление всех путей, содержащихcygwin
)
pattern=cygwin; export PATH=$(echo $PATH|tr ':' '\n'|sed "\#${pattern}#d" |tr '\n' ':')
Этот метод обрабатывает разделитель начального/конечного пути:
echo $PATH | sed 's/:/\n/g' | grep -v <path description> | xargs | tr ' ' ':'
Пояснение:
echo
переменная $PATH в sed
, которая заменяет ':' символом новой строки
grep
вывод и удаление строк, соответствующих нашему запросу
xargs
вывод для замены новых строк пробелами
tr
вывод для замены пробелов двоеточиями
xargs
выполняет обрезку конечных значений
объединить несколько grep
s, чтобы удалить несколько путей
Можно использовать регулярные выражения 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
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
}
Я использую функции Стивена Коллиера 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
Баш Oneliner построен -в:
DIR=/dir/to/remove
PATH=${PATH/${PATH/#$DIR:*/$DIR:}/}${PATH/${PATH/*:$DIR*/:$DIR}/}
/
с чем-то как|
:PATH=$(echo "$PATH" | sed -e 's|:/d/Programme/cygwin/bin$||')
предотвратить весь выход. – Matthias Kuhn 17.03.2016, 14:06