从PATH删除目录


28

我正在尝试使用MingW编译wxWidgets,并且我的路径中存在cygwin,这似乎冲突。所以我想/d/Programme/cygwin/bin从PATH变量中删除,我想知道是否有某种优雅的方法可以做到这一点。

幼稚的方法是将其回显到文件,手动将其删除并获取它,但是我敢说有更好的方法。


2
此处列出了许多技术:stackoverflow.com/questions/370047/…–
slm

Answers:


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 2014年

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

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
}

这最终与Gilles的解决方案非常接近,但被打包为bash函数,可以在命令行上轻松使用。

它的优点是,作为bash函数,它就像程序一样工作,而不必成为路径上的程序,并且不需要运行任何外部程序,只需操作bash字符串即可。

它看起来很健壮,尤其是它不会somepath:mypath/mysubpath变成somepath/mysubpath:if run path_remove mypath,这是我以前的path_remove函数遇到的一个问题。

可以在《高级Bash脚本指南》中找到有关bash字符串操作原理的出色解释。


6

因此,结合@gilles和@ bruno-a的答案(以及其他一些sed技巧),我想到了这个单行代码,它将从PATH中删除(每个)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命令添加的前导和尾随冒号)

沿着类似的思路,当PATH中尚未包含ADD_PART时,我才设法将其添加到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)

整洁,即使我自己说:-)


我喜欢这个建议,尤其是脚本的想法。
Devolus

3

一个简单得多的班轮。

导出PATH =`echo $ PATH | tr“:”“ \ n” | grep -v“ anaconda” | 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

以下是Greg Tarsa解决方案的修订代码。这里仅使用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按照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' ':')
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.