从 bash 脚本无需 PATH 即可运行命令的可移植方法

从 bash 脚本无需 PATH 即可运行命令的可移植方法

cron 使用非常稀疏的 PATH 调用我的 bash 脚本(它是一个备份脚本)/usr/bin:/usr。结果,虽然像这样的行

lvcreate --size 1G --snapshot ...

当我从终端运行脚本时工作得很好,如果从 crontab 运行,它找不到 lvcreate。描述了类似的问题这里,但我对处理根本问题的一般策略更感兴趣。

到目前为止我想到的想法:

  • 作为一种快速解决方法,我在脚本顶部手动设置 PATH。我也可以在 crontab 中执行此操作。如果系统范围的 PATH 发生变化,我可能需要手动更新所有这些行。

  • 一个更永久的解决方案是在我的脚本中使用绝对路径,例如用类似的东西替换调用,/sbin/lvcreate --size 1G ...但是虽然这可以在我第一次遇到这个问题的 Ubuntu 服务器上工作,但在我的 Arch Linux ARM (RPi) 上 lvcreate 位于 / usr/bin/.

  • 我可以which正确设置 PATH 的每个命令,存储结果并在脚本顶部设置本地别名,但这对我来说似乎有点混乱。

  • 我考虑过采购/etc/environment。这适用于我的 Ubuntu 机器(我认为也适用于普通的 debian),但在我的 RPi 上,系统范围的 PATH 没有在那里设置。出于同样的原因(不想依赖于各种发行版中某些文件的位置和/或使用),我对使用 .bashrc 或类似文件犹豫不决。

所以我的问题是:什么是使脚本不依赖于设置的 PATH 并仍然保持可移植性的好方法?有最先进的方法吗?

答案1

明确设置PATH

如果您从脚本中执行此操作,则可以添加到 的当前设置$PATH,然后您将尊重其中的任何内容,并且只需添加您想要确保不丢失的内容:

#!/bin/bash
PATH=$PATH:/sbin:/usr/sbin:/usr/local/bin:/usr/local/sbin
...

也许在 crontab 配置中设置更合适PATH(您可以在那里设置环境变量),因为实际上您正在解决 cron 本身的缺点,所以也许在 cron 中修复它比修改脚本更有意义。

如果您在 cron 中设置它,则需要完成PATH设置,因为您无法从那里引用其当前值:

# my user's crontab
PATH=/bin:/usr/bin:/usr/local/bin:/sbin:/usr/sbin:/usr/local/sbin

0 2 * * * /usr/local/bin/my2amjob.sh

(您可能需要稍微不同的目录顺序,具体取决于您的某些系统或您自己最终是否为安装在稍后列出的目录中的较简单版本安装“覆盖” $PATH,但请检查您的系统当前设置的内容,看看是否可以调和一下。)

希望这能解决您的问题。

如果系统范围的 PATH 发生变化,我可能需要手动更新所有这些行。

坦白说,我不会对此太担心。您的分发包将始终将其二进制文件安装在/usr/bin/usr/sbin/bin/sbin,因此您始终能够访问它们而无需更改任何路径。发行版长期以来认为更新$PATH以包含新目录是一场噩梦,因此他们一直在避免这种情况,bin而是向主目录添加符号链接或包装脚本。

对于您自己安装的软件,建议更新$PATH,我建议这样做,在下面创建符号链接或包装器脚本,并尽可能/usr/local/bin避免更改。$PATH


Linux 发行版也正在采取一些措施来解决这些差异$PATH问题。

首先是/usr合并努力,它变成/bin的符号链接/usr/bin/sbin变成 的符号链接/usr/sbin。所有二进制文件都安装在/usr(对打包者来说更容易)下,但脚本仍然通过某些绝对路径引用它们,例如/bin/mytool/sbin/mytool将继续通过符号链接工作。这已经被 Fedora 和 ArchLinux 等发行版所采用,而 Debian 和 Ubuntu 等其他发行版目前也正在经历采用的步骤。

ArchLinux 似乎更进了一步,它已经合并在一起sbinbin。因此,在采用合并的现代 ArchLinux 中,您可以通过四个可能的绝对路径中的任何一个来引用二进制文件,然后您就会找到它们。还有待观察其他发行版是否也会采用第二次合并。


最后,您可能需要考虑 cron 的更现代的替代方案。 Cron 有很多特性,比如您正在经历的裸露环境,但也使用电子邮件进行命令输出(而不是使用日志系统)和尴尬的命令行转义。

你提到了Ubuntu和ArchLinux,它们都支持内置的systemd定时器,无需安装任何软件包。

您可能需要查看 ArchLinux wiki,其中有关于如何使用它们的优秀文章。特别是,您可能想检查使用 systemd 计时器作为 cron 替代品,它具有特定的配方,可能对您的特定用例非常有用。

相关内容