PATH(环境变量)中的通配符

PATH(环境变量)中的通配符

我在我的主目录中本地安装了一堆应用程序。为了使它们在全球范围内可用,我将它们添加PATH.bashrc

PATH="$PATH:/home/user/apps/app1/bin"
PATH="$PATH:/home/user/apps/app2/bin"
PATH="$PATH:/home/user/apps/appn/bin"

我该如何设置才能不必添加每个新的?我正在尝试这个,但它不起作用:

PATH="$PATH:/home/user/apps/*/bin"

笔记:我知道我可以用循环添加它们,但我也担心我的PATH变量会变得太大,我想知道是否可以以某种方式使用通配符。

答案1

通配符不会在$PATH, no 中扩展。根据bash手册,路径是:

以冒号分隔的列表目录shell 在其中查找命令

(我的重点)。

从另一个方向过来,命令搜索和执行部分该手册的部分内容是:

如果名称既不是 shell 函数也不是内置函数,并且不包含斜杠,Bash 会在 $PATH 的每个元素中搜索目录包含具有该名称的可执行文件。

...(我的重点)——它没有提到对路径元素进行的任何特殊处理,只是说它们应该是目录(按原样)。

我暂时不确定 bash 变量的大小限制是多少;我怀疑它是可用内存。 PATH不需要导出,但很多人都这样做;如果它被导出,它需要与其他环境变量和参数一起适应getconf ARG_MAX(参考:https://unix.stackexchange.com/a/124422/117549)。大型 PATH 目录不应引起太多性能开销,因为 bash 使用哈希表来记住先前找到的命令(每个会话)的位置。

如果您在将每个单独的应用程序目录添加到 PATH 时确实遇到了限制(视觉或技术),我建议您向 PATH 添加一个“符号链接”目录,然后您可以在其中链接来自各个应用程序的所需可执行文件。

答案2

添加/home/user/apps/*/bin到意味着$PATH在路径为/home/user/apps/*/bin(完全有效的路径,没有什么可以阻止*字符 1 在 Unix 上的文件或目录的名称中使用)的目录中搜索可执行文件,您可以添加/home/user/apps/*/bin当时路径匹配的目录的写作使用:

path+=( /home/user/apps/*/bin(N-/) )

在 zsh 中,变量与 csh 中的数组$PATH绑定,并且glob 限定符可用于限制对目录类型文件(或目录的符号链接)的扩展,以及nullglob$path-/N

您还可以发出 atypeset -U path来删除重复项(U对于唯一)。

在 中fish,其中$PATH公开为数组,并且类似 nullglob 的行为应用于 中使用的 glob set

set PATH $PATH /home/user/apps/*/bin

(不限于类型的文件目录尽管)。

POSIXly,你总是可以这样做:

for dir in /home/user/apps/*/bin; do
  [ -d "$dir" ] && PATH="${PATH:+$PATH:}$dir"
done

无论如何,如果以后将更多目录添加到 /home/user/apps/ 中,它们将不会自动出现在$PATH.

在 ksh93 中,您可以使用规则来实现这种神奇的效果:

function PATH.get {
  typeset dir
  for dir in ~(N)/home/user/apps/*/bin; do
    [[ :$PATH: = *:"$dir":* || ! -d $dir ]] || PATH=${PATH:+$PATH:}$dir
  done
}

$PATH每次引用时都会计算的值。

在 zsh 中,您可以在每次提示之前使用precmd()钩子或bash使用重新计算它$PROMPT_COMMAND


¹ 或除 和 NUL 之外的任何字符/,甚至是与此相关的非字符。

答案3

我为此使用了一些解决方案:

1.使用find动态生成$PATH

为此,我使用了几种类似但略有修改的方法。假设您有以下结构:

~/apps
├── foo
│   └── bin
├── bar
│   └── bin
└── blah

我们可以...

A。添加现有的应用程序/*/bin/文件夹到$PATH

这将搜索任何垃圾桶/目录在$HOME/应用/*并将它们添加到$PATHshell 加载时,跳过任何没有的目录垃圾桶/子目录。

#.bashrc

bins=$(
    find "$HOME/apps/" -maxdepth 2 -type d -name 'bin' \
        | tr '\n' ':' \
        | sed 's/:$//'
)
export PATH="$bins:$PATH"

生产:

/home/user/apps/foo/bin:/home/user/apps/bar/bin:...

b.添加任何某个目录/*/bin/$PATH

...无论每个文件夹是否某个目录/实际上有一个垃圾桶/里面的子目录。这意味着,对于上面的目录结构,甚至应用程序/等等/bin将被添加到$PATH-- 即使它不存在!

当您的目录之一不存在时,这很有用现在有一个垃圾桶/子目录,但它很可能在将来,并且您不希望$PATH在创建它后必须重新加载 shell 才能将其添加到您的 shell 中。

#.bashrc

bins=$(
    find "$HOME/apps/" -maxdepth 1 -type d \
        | sed 's_$_/bin_' \
        | tr '\n' ':' \
        | sed 's/:$//'
)
export PATH="$bins:$PATH"

生产:

/home/user/apps/foo/bin:/home/user/apps/bar/bin:/home/user/apps/blah/bin:...

由于命令查找将短暂尝试查找不存在的目录,因此可能会对性能产生可笑的忽略不计的影响感觉将不存在的目录添加到 my 是不好的$PATH,但从方便起见,这是我的首选选择。

2. 用于stow生成可执行文件的符号链接

stow正是为了这个目的而创建的。我目前正在使用此设置将所有点文件存储在 git 存储库中并将它们复制到我的主目录:)

如果您有如下目录结构:

.
├── bar
│   └── bin
│       ├── bar-executable-1
│       └── bar-executable-2
├── bin
└── foo
    └── bin
        ├── foo-executable-1
        └── foo-executable-2

你想要所有的文件酒吧/垃圾箱/*富/bin/*链接到垃圾桶/,你可以运行:

cd somedir
stow -v --restow --target bin/ --dir bar/ bin
stow -v --restow --target bin/ --dir foo/ bin

注意:我用于--restow修剪,因为它会在重新创建新的符号链接之前先删除所有旧的符号链接

这会生成:

somedir
├── bar
│   └── bin
│       ├── bar-executable-1
│       └── bar-executable-2
├── bin
│   ├── bar-executable-1 -> ../bar/bin/bar-executable-1
│   ├── bar-executable-2 -> ../bar/bin/bar-executable-2
│   ├── foo-executable-1 -> ../foo/bin/foo-executable-1
│   └── foo-executable-2 -> ../foo/bin/foo-executable-2
└── foo
    └── bin
        ├── foo-executable-1
        └── foo-executable-2

然后你可以简单地添加某个目录/bin/给你的PATH

使stow使用更容易一些

如果

  1. 每个目录中唯一的目录应用程序N目录是单个垃圾桶/目录
  2. 你可以移动编译的垃圾桶/您的目录之外的目录应用/目录

那么你可以使用一个稍微简单的stow命令:

/home/user
├── Desktop
├── Documents
├── Pictures
├── Videos
├── apps
│   ├── bar
│   │   └── bin
│   │       ├── bar-executable-1
│   │       └── bar-executable-2
│   └── foo
│       └── bin
│           ├── foo-executable-1
│           └── foo-executable-2
└── bin
cd
stow -v --restow --target ./ --dir apps/ foo bar

这基本上说的是在“apps”文件夹中查找名为“foo”和“bar”的“packages”,然后使用符号链接将这两个包的全部内容复制到当前目录。所以如果你拥有的一切应用程序/foo/应用程序/栏/是单身垃圾桶/文件夹,然后这会生成一个垃圾桶/当前目录中的文件夹,其中包含指向所有文件的链接应用程序/foo/bin/应用程序/栏/bin/

但是,如果您还有很多其他文件/文件夹应用程序/foo/应用程序/栏/除了单一的垃圾桶/目录,然后它也会在您的主文件夹中重新创建所有这些内容,这可能是不可取的,您应该坚持使用第一个stow示例。

https://www.gnu.org/software/stow/manual/html_node/Installing-Packages.html

相关内容