【问题标题】:PATH in post-receive hook doesn't contain PATH as set in bashrc接收后挂钩中的 PATH 不包含 bashrc 中设置的 PATH
【发布时间】:2019-02-25 16:34:34
【问题描述】:

如何在 Ubuntu 上设置 PATH,使我设置的变量也在接收后脚本中设置?目前我正在通过~/.bashrc 文件这样做:

export PATH="$PATH:/opt/mssql-tools/bin"

但是如果我从钩子中打印它,PATH 看不到任何变化。因此,如果我尝试在钩子中执行有问题的命令,我会得到

remote: FileNotFoundError: [Errno 2] No such file or directory: 'sqlcmd': 'sqlcmd'

所以我现在看到的唯一解决方案是在 post-receive 钩子本身中再次定义它,如下所示:

export PATH="$PATH:/opt/mssql-tools/bin"

有没有更好的办法?

谢谢!

【问题讨论】:

  • 如果您正在寻找更好的方法,请编辑您的帖子以包含显示您当前执行方式的特定代码。
  • 这感觉有点像X-Y problem。我猜您怀疑 PATH 是错误的,因为找不到某些可执行文件或其他文件,对吗?那么那个可执行文件是什么?钩子脚本中的 PATH 只需定义一个 PATH ,其中包括钩子脚本将使用的所有可执行文件。如果您可以枚举它需要的所有可执行文件,那么您将在构建包含这些文件的PATH= 命令方面取得很大进展。钩子脚本中有哪些可执行文件失败了?
  • 我怀疑根本问题是$PATH 的初始值在您登录并运行 .bashrc 时与钩子脚本运行时不同。要么清点你的钩子使用的可执行文件列表,并指定一个允许它找到这些可执行文件的路径;或者你可以减少/消除你对钩子脚本中PATH的依赖,并为你需要的可执行文件指定绝对PATHs。
  • 至于“为什么”部分,这就是 bash 的工作方式。手册页记录了 interactive shell(当连接了终端时),bash 在启动时读取 .bashrc。对于非交互式 shell(如脚本),它不会读取 .bashrc。此外,交互式 bash shell 读取的 .bashrc 属于运行 shell 的用户,因此即使钩子具有 was 交互式,它也可能在 wwwgit 用户帐户,而不是您自己的帐户。
  • 快速阅读 bash 手册页表明它将查找环境变量 BASH_ENV 并将其视为(完整的、绝对的)文件名来读取和执行。

标签: bash path git-post-receive


【解决方案1】:

首先,一点文件设置:

$ mkdir /tmp/dir1 /tmp/dir2
$ date > /tmp/dir1/foo
$ date > /tmp/dir2/bar

现在,考虑一个简单的脚本:

$ chmod 755 foo.sh; cat foo.sh
#!/bin/sh

# intentionally set an inadequate PATH:

export PATH=""    

# script to 'ls' two dirs, show that output, and show the diff of the two.

ls /tmp/dir1 > temp1
ls /tmp/dir2 > temp2

echo /tmp/dir1:
cat temp1

echo /tmp/dir2:
cat temp2

diff temp1 temp2

该脚本在语法上格式正确,但让我们看看会发生什么:

$ ./foo.sh
./foo.sh: ls: not found
./foo.sh: ls: not found
/tmp/dir1:
./foo.sh: cat: not found
/tmp/dir2:
./foo.sh: cat: not found
./foo.sh: diff: not found

路径不足以让脚本解释器找到脚本要运行的可执行文件。三个单独的可执行文件无法加载:lscatdiff。所以让我们帮一点忙。由于ls 通常位于/bin 目录中,我们将PATH 编辑为:

export PATH="/bin"

再试一次:

$ ./foo.sh
/tmp/dir1:
foo
/tmp/dir2:
bar
./foo.sh: diff: not found

好吧,ls 现在可以正常运行了。这就是进步。并且由于cat 也住在/bin 中,因此将/bin 添加到路径中,用一块石头杀死了两只鸟。但是diff 仍然找不到,因为diff 位于/usr/bin 中。因此,让我们将其添加到 PATH:

export PATH="/bin:/usr/bin"

再试一次:

$ ./foo.sh 
/tmp/dir1:
foo
/tmp/dir2:
bar
1c1
< foo
---
> bar

瞧!没有更多错误,因为PATH 变量包含允许脚本解释器定位脚本调用的可执行文件所需的所有内容。

另一种方法是告诉PATH 退出并指定您自己的可执行文件路径。当您出于某种原因可能不信任或不希望“标准”可执行文件时,此方法有时会很方便。当以这种方式构建脚本时,我更喜欢为我想引用的可执行文件使用变量,这样如果位置发生变化,我可以只更改变量,而不必搜索整个脚本该可执行文件的调用。

$ chmod 755 bar.sh; cat bar.sh
#!/bin/sh

# intentionally set an inadequate PATH:

export PATH=""

# ls lives in /bin:
LS="/bin/ls"

# so does cat:
CAT="/bin/cat"

# but diff lives in /usr/bin:
DIFF="/usr/bin/diff"

# script to 'ls' two dirs, show that output, and show the diff of the two.

$LS /tmp/dir1 > temp1
$LS /tmp/dir2 > temp2

echo /tmp/dir1:
$CAT temp1

echo /tmp/dir2:
$CAT temp2

$DIFF temp1 temp2

还有输出:

$ ./bar.sh
/tmp/dir1:
foo
/tmp/dir2:
bar
1c1
< foo
---
> bar

您可以混合和匹配这些方法,方法是指定包含大多数内容的 PATH,并为其他内容指定绝对路径,但您的问题出现了,因为您没有这样做。

您需要在钩子脚本中指定完整且足够的PATH,和/或指定位于钩子脚本当前使用的任何PATH 变量之外的剩余可执行文件(如果有)的绝对路径。

【讨论】:

    猜你喜欢
    • 2016-10-04
    • 1970-01-01
    • 2013-08-20
    • 2014-09-07
    • 2016-10-19
    • 1970-01-01
    • 2019-02-10
    • 2013-01-05
    • 1970-01-01
    相关资源
    最近更新 更多