一种编辑长$ PATH的更舒适的方法?


35

我想在〜/ .bashrc中向$ PATH添加一些目录。

我的$ PATH很长,因此很难查看它包含的目录和顺序。

我知道我可以将〜/ .bashrc修改为:

PATH=$PATH:/some/dir
PATH=$PATH:/another/dir:/yet/another
PATH=$PATH:/and/another
...

这将使其更易于阅读。但是我想知道在过去的几年中Bash是否获得了一些使指定长路径更容易的语法。例如,我幻想的语法类似于:

PATH=:((
  /some/dir
  /another/dir
  /yet/another
  /and/another
  ...
))

知道这样的语法是无效的。我想知道是否有那么容易的事情。在那儿?


传统的教程设置通过路径PATH=foo:$PATH,因为它每次都保持增长似乎是错误的source ~/.bashrc,甚至exec bash不能帮助,因为$PATHexport
林果皞

Answers:


25

我使用一组便利函数在变量之前或之后添加路径。这些功能位于Bash的分发压缩包中,位于一个名为“ pathfuncs”的contrib文件中。

  • add_path会将条目添加到PATH变量的末尾
  • pre_path会将条目添加到PATH变量的开头
  • 无论在何处,del_path都会从PATH变量中删除该条目

如果将变量指定为第二个参数,它将使用该变量而不是PATH。

为了方便起见,它们是:

# is $1 missing from $2 (or PATH) ?
no_path() {
    eval "case :\$${2-PATH}: in *:$1:*) return 1;; *) return 0;; esac"
}
# if $1 exists and is not in path, append it
add_path () {
  [ -d ${1:-.} ] && no_path $* && eval ${2:-PATH}="\$${2:-PATH}:$1"
}
# if $1 exists and is not in path, prepend it
pre_path () {
  [ -d ${1:-.} ] && no_path $* && eval ${2:-PATH}="$1:\$${2:-PATH}"
}
# if $1 is in path, remove it
del_path () {
  no_path $* || eval ${2:-PATH}=`eval echo :'$'${2:-PATH}: |
    sed -e "s;:$1:;:;g" -e "s;^:;;" -e "s;:\$;;"`
}

如果将它们添加到bash启动文件中,则可以将其添加到PATH中,如下所示:

pre_path $HOME/bin
add_path /sbin
add_path /usr/sbin

或指定其他变量:

pre_path $HOME/man MANPATH
pre_path $HOME/share/man MANPATH
add_path /usr/local/man MANPATH
add_path /usr/share/man MANPATH

我在rc文件中使用此方法,将pre_paths首先放置,将add_paths其次放置。一目了然,这使我所有的路径变化都易于理解。另一个好处是,行足够短,可以在必要时在行上添加尾随注释。

而且由于这些功能,您可以从命令行以交互方式使用它们,例如说add_path $(pwd)将当前目录添加到路径。


谢谢。我已经检查了您的代码,它可以工作。令人惊讶的是,我还发现了del_path的用法(在某些情况下,A“。”会渗入我的PATH中,魔鬼从哪里知道,所以我这样做了del_path .)。
Niccolo M.

你好 可以从bashrc脚本中获取(包括)此pathfuncs还是应该将它们复制/粘贴到那里?
克里斯蒂亚诺

@Cristiano Either会工作。完全取决于您。
海星

11

好的,我想出了以下解决方案,我认为这很不错(就shell语法而言)。它使用Bash的数组语法,也是连接元素的一种巧妙方法

paths=(
  /some/dir
  /another/dir
  '/another/dir with spaces in it'
  /yet/another
  /and/another
  /end
)
paths_joined=$( IFS=: ; echo "${paths[*]}" )

PATH=$paths_joined:$PATH

警报!

事实证明,此解决方案有一个问题:与@terdon和@Starfish的解决方案不同,它不首先检查路径是否已经在PATH中。因此,由于我要将这段代码放在〜/ .bashrc中(而不是〜/ .profile中),因此重复的路径将蔓延到PATH中。因此,请勿使用此解决方案(除非您将其放在〜/ .profile中(或者最好将〜/ .bash_profile放入Bash特定语法中))。


1
非常好。您能接受一个答案,以便其他人在找到答案后不来这里提供解决方案吗?谢谢
基本的

重复的路径并不是真正的问题。您极不可能添加足够的目录来PATH实际导致性能问题(特别是因为Shell缓存了成功的查找)。
chepner

5

我在中使用以下功能~/.bashrc。这是我从旧实验室的系统管理员那儿得到的东西,但我不认为他是他们写的。只需将这些行添加到您的~/.profile或中~/.bashrc

pathmunge () {
        if ! echo $PATH | /bin/grep -Eq "(^|:)$1($|:)" ; then
           if [ "$2" = "after" ] ; then
              PATH=$PATH:$1
           else
              PATH=$1:$PATH
           fi
        fi
}

这具有各种优点:

  • 添加新目录到$PATH很简单:pathmunge /foo/bar;
  • 它避免重复的条目;
  • 您可以选择是否将新条目添加到的开头(pathmunge /foo/bar或结尾pathmunge /foo/bar$PATH

Shell的初始化文件将包含以下内容:

pathmunge /some/dir
pathmunge /another/dir
pathmunge '/another/dir with spaces in it'
pathmunge /yet/another
pathmunge /and/another
pathmunge /end

谢谢。但是我会选择@Starfish的解决方案,因为他不会生成grep
Niccolo M.

2
@NiccoloM。没问题,接受您喜欢的任何一个。不过,请谨慎使用starfish的方法,因为它将执行任意代码,eval因此如果使用错误的参数运行它,可能会造成严重的损害。
terdon

请注意,redhat中存在更快的功能,无需外部命令即可执行此操作grep,请参见bugzilla.redhat.com/show_bug.cgi?id=544652#c7
林果皞

4

我想在〜/ .bashrc中向$ PATH添加一些目录。

我在Cygwin中使用以下内容。它应该可以在其他bash版本中使用。您可以删除,unset PATH以在当前版本的基础上构建PATH(如果这样做,则可能必须弄清楚如何:正确添加分隔符)。

注意:

  • 我曾经在某个bash功能中拥有此功能,但在磁盘崩溃后丢失了它。

在我的.bash_profile

# Build up the path using the directories in ~/.path_elements
unset PATH
while read line; do 
  PATH="${PATH}$line"; 
done < ~/.path_elements

...

# Add current directory to path
export PATH=".:${PATH}"

~/.path_elements

/home/DavidPostill/bin:
/usr/local/bin:
/usr/bin:
/c/Windows/system32:
/c/Windows

谢谢。您的回答激发了我从事类似解决方案的工作。(按照我的口味,将路径存储在单独的文件中是一件麻烦的事。)
Niccolo M.

1

我在我的.bashrc(以及我的.zshrc中使用了它,因为我通常在可用的地方使用zsh而不是bash)。当然,这需要我手动添加目录,但是一个优点是,在更新目录时,我可以将其不断复制到新服务器上,而不必担心在不存在目录的新服务器上创建PATH。

##
##路径
##
##而不是仅仅用可能破坏目录的方式破坏我们的PATH
##不适合此服务器,请对我们添加的内容保持明智
##
路径= / usr / local / sbin:/ usr / local / bin:/ usr / sbin:/ usr / bin:/ sbin:/ bin
[-d / cs / sbin] && PATH = / cs / sbin:$ PATH
[-d / cs / bin] && PATH = / cs / bin:$ PATH
[-d / usr / ucb] && PATH = $ PATH:/ usr / ucb
[-d / usr / ccs / bin] && PATH = $ PATH:/ usr / ccs / bin
[-d / usr / local / ssl / bin] && PATH = $ PATH:/ usr / local / ssl / bin
[-d / usr / krb5 / bin] && PATH = $ PATH:/ usr / krb5 / bin
[-d / usr / krb5 / sbin] && PATH = $ PATH:/ usr / krb5 / sbin
[-d / usr / kerberos / sbin] && PATH = $ PATH:/ usr / kerberos / sbin
[-d / usr / kerberos / bin] && PATH = $ PATH:/ usr / kerberos / bin
[-d /cs/local/jdk1.5.0/bin] && PATH = $ PATH:/cs/local/jdk1.5.0/bin
[-d /usr/java/jre1.5.0_02/bin] && PATH = $ PATH:/usr/java/jre1.5.0_02/man
[-d /usr/java1.2/bin] && PATH = $ PATH:/usr/java1.2/bin
[-d /cs/local/perl5.8.0/bin] && PATH = $ PATH:/cs/local/perl5.8.0/bin
[-d / usr / perl5 / bin] && PATH = $ PATH:/ usr / perl5 / bin
[-d / usr / X11R6 / bin] && PATH = $ PATH:/ usr / X11R6 / bin
[-d / etc / X11] && PATH = $ PATH:/ etc / X11
[-d / opt / sfw / bin] && PATH = $ PATH:/ opt / sfw / bin
[-d / usr / local / apache / bin] && PATH = $ PATH:/ usr / local / apache / bin
[-d / usr / apache / bin] && PATH = $ PATH:/ usr / apache / bin
[-d / cs / admin / bin] && PATH = $ PATH:/ cs / admin / bin
[-d / usr / openwin / bin] && PATH = $ PATH:/ usr / openwin / bin
[-d / usr / xpg4 / bin] && PATH = $ PATH:/ usr / xpg4 / bin
[-d / usr / dt / bin] && PATH = $ PATH:/ usr / dt / bin

我为MANPATH做同样的事情:

##
## MANPATH
##
##而不是仅仅用可能破坏目录的方式破坏我们的MANPATH
##不适合此服务器,请对我们添加的内容保持明智
##
MANPATH = / usr /本地/ man
[-d / usr / share / man] && MANPATH = $ MANPATH:/ usr / share / man
[-d / usr / local / share / man] && MANPATH = $ MANPATH:/ usr / local / share / man
[-d / usr / man] && MANPATH = $ MANPATH:/ usr / man
[-d / cs / man] && MANPATH = $ MANPATH:/ cs / man
[-d / usr / krb5 / man] && MANPATH = $ MANPATH:/ usr / krb5 / man
[-d / usr / kerberos / man] && MANPATH = $ MANPATH:/ usr / kerberos / man
[-d / usr / local / ssl / man] && MANPATH = $ MANPATH:/ usr / local / ssl / man
[-d /cs/local/jdk1.5.0/man] && MANPATH = $ MANPATH:/cs/local/jdk1.5.0/man
[-d /usr/java/jre1.5.0_02/man] && MANPATH = $ MANPATH:/usr/java/jre1.5.0_02/man
[-d /usr/java1.2/man] && MANPATH = $ MANPATH:/usr/java1.2/man
[-d / usr / X11R6 / man] && MANPATH = $ MANPATH:/ usr / X11R6 / man
[-d / usr / local / apache / man] && MANPATH = $ MANPATH:/ usr / local / apache / man
[-d / usr / local / mysql / man] && MANPATH = $ MANPATH:/ usr / local / mysql / man
[-d /cs/local/perl5.8.0/man] && MANPATH = $ MANPATH:/cs/local/perl5.8.0/man
[-d / usr / perl5 / man] && MANPATH = $ MANPATH:/ usr / perl5 / man
[-d / usr / local / perl / man] && MANPATH = $ MANPATH:/ usr / local / perl / man
[-d /usr/local/perl5.8.0/man] && MANPATH = $ MANPATH:/usr/local/perl5.8.0/man
[-d / usr / openwin / man] && MANPATH = $ MANPATH:/ usr / openwin / man

除了可以将一个文件复制到不同环境中的系统而不必担心将不存在的目录添加到PATH之外,这种方法还具有允许我指定希望目录在PATH中出现的顺序的优点。由于每个定义的第一行都完全重新定义了PATH变量,因此我可以更新.bashrc并在编辑后获取它的源代码,以更新我的shell,而无需添加重复的条目(我很久以前曾以“ $ PATH = $ PATH:/ new / dir”。这样可以确保我按期望的顺序获得干净的副本。


1
建议一个替代方案: d="/usr/share/man" ; [ -d "$d" ] && MANPATH="$MANPATH:${d}"添加新目录将更短,更容易(只需复制一行并编辑第一个“ d = ....”部分)。但是,对于PATH,我认为您最终会在PATH中遇到太多Dirs,这并不总是一件好事(如果在鲜为人知的路径之一中存在某些“ foo”命令,并且会执行完全不同的操作普通用户会期望什么?)
Olivier Dulac

OP要求一种更简洁的添加路径的方法。比他们已经尝试避免的更加冗长,更容易出错。
underscore_d 2015年

-1

有一个简单的方法!读Shell函数和路径变量Linux杂志2000年3月1日由斯蒂芬哥烈

这些函数使我可以在bash环境中使用新的数据类型-冒号分隔的列表。除了PATH外,我还使用它们来调整我的LOCATE_PATH,MANPATH等,并作为bash编程中的常规数据类型。这是我使用功能设置PATH的方法:

# Add my bin directory to $PATH at the beginning, so it overrides 
addpath -f -p PATH $HOME/bin

# For Raspberry Pi development (add at end)
addpath -b -p PATH ${HOME}/rpi/tools/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian-x64/bin

# remove nonexistent directories from PATH
delpath -n -p PATH

# ensure PATH contains unique entries
uniqpath -p PATH

由于Linux Journal链接被称为“断开”,因此我已将Bash路径函数放置在http://pastebin.ubuntu.com/13299528/上的.shar文件中。


3
这些是什么功能?OP如何使用它们?大概在答案的断开链接中描述了它们,这正是我们始终希望答案独立的原因。请编辑实际功能并将其包含在您的答案中。
terdon

@terdon:链接对我有用,我将一个.shar文件放在pastebin上,我不会在此处发布1K行。
waltinator 2015年

哎呀,现在也为我工作。当我发表评论时没有。无论如何,我评论的要旨是我们试图避免在答案中链接到外部资源。我们希望这些信息可以在此处进行更新,编辑,并且不会造成链接腐烂。
terdon 2015年
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.