编辑长 $PATH 的更舒适的方法是什么?

编辑长 $PATH 的更舒适的方法是什么?

我想在 ~/.bashrc 中将一些目录添加到我的 $PATH。

我的 $PATH 很长,因此很难看出它包含哪些目录以及包含的顺序。

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

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

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

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

知道这样的语法是无效的。我想知道是否有同样简单的方法。有吗?

答案1

我使用一组便利函数来将路径添加到变量的前面或后面。这些函数位于 Bash 的分发包中,位于名为“pathfuncs”的贡献文件中。

  • 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)当前目录添加到路径中。

答案2

好的,我想出了以下解决方案,我认为它很优雅(就 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 特定语法))。

答案3

我在我的 中使用了下面的函数~/.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

答案4

我在 .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=/usr/local/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”开始时,我就遇到过这种情况)。这确保我按照我想要的顺序获得干净的副本。

相关内容