当我启动 shell 时如何确定程序是否正在运行,如果程序尚未运行则启动该程序?

当我启动 shell 时如何确定程序是否正在运行,如果程序尚未运行则启动该程序?

当我启动 shell 时,在我的例子中是 bash 和/或 zsh,我需要向 .zshrc 和/或 .bashrc 添加哪些行来检查程序是否已经在运行,以及程序是否尚未运行,启动它?

示例:我正在启动一个新的 zsh shell。如果 top 尚未运行,我想启动 top 并让它接管 shell。如果 top 已经在另一个窗口中运行,我希望 .zshrc 继续加载并给我一个打开的终端。

6-16更新:

if ! pgrep -U $USER top >/dev/null; then
exec top
fi

上面的脚本满足了我的要求。 -q 标志对我不起作用,因为 -q 不是我的系统上的选项。所以我必须将 PID 通过管道传输到 /dev/null。谢谢 mveroone、Kusalananda 和 Thomas Dickey。

我有一些功能蔓延超出了原始问题的范围。假设我在单用户系统上,无需输入密码即可成为 root 用户。如果需要的话,我如何以root身份自动运行top?

6-18 好的,以 root 身份传递命令的功能蔓延问题已解决。我用它来启动几个

感谢您所有深思熟虑的回复。

答案1

pgrep像这样使用:

if ! pgrep -u $USER top >/dev/null 2>&1; then
    exec top
fi

解释:

  • pgrep如果发现该命令正在运行,则实用程序将以零退出代码退出。因此,否定该测试。
  • 还可以使用 来将其限制为当前用户-u $USER,这样它就不会因为某种原因而获取其他人的进程。$USER是一个标准的 shell 变量。如果由于某种原因未定义,请尝试使用$LOGNAME,如果失败,请使用$( id -n -u )(但此时您必须问自己发生了什么事,因为$LOGNAME标准 shell 变量)。
  • 我们不需要 的输出pgrep,因此将标准输出和错误流重定向到/dev/null

如果top(或其他)未发现正在运行,则exec根据OP的问题,它会替换外壳。

这应该适用于所有sh兼容的 shell。

编辑:pgrepBSD 系统(OS X,OpenBSD,...)上的实现有一个-q选项可以让它丢弃任何输出,但pgrepLinux 上显然没有这个标志。在 BSD 系统上,使用这个而不是稍微难看的重定向到/dev/null.

答案2

如果程序始终从 shell 启动并且您可以完全控制它(即它没有在第 3 方程序中硬编码),那么您可以使用某种锁定机制,例如lockfileflock。例如通过添加

flock -n /tmp/top -c top

.bashrc/.zshrc您将确保只有 shell 的第一个实例将运行该top命令(除非您杀死它,然后将启动另一个实例)。

您可能想要创建一个函数,以便能够手动启动命令(不仅仅是在 shell 初始化时):

mytop () { flock -n /tmp/$0 -c top; }

mytop只要你想跑就跑。

答案3

同意这pgrep是要走的路,但也存在一些陷阱。您不需要使用该-q选项,因为您可以重定向输出pgrep来消除该问题:

pgrep -U $USER top >/dev/null || exec top

陷阱在于它不是标准实用程序,因此您必须记住它可能不可移植。以下是一些帮助页面链接:

环境USER变量更加完善,但似乎不在 POSIX 的 shell 列表中(请参阅2.5.3 Shell 变量)。相反,它指出这USER是已知正在使用的许多变量之一(参见注释8.1 环境变量定义)。

这运行top你自己, 当然。如果您选择让它运行为,然后您可以将 更改$USER为然后使用(首选)或root运行。 POSIX 中都不存在(topsudosu查看列表)。后者 ( su) 在类 Unix 系统上随处可用,但sudo通常是首选。所以你会有

pgrep -U root top >/dev/null || exec sudo top

除非您已配置sudo为不需要密码,否则 shell 启动时将提示您输入密码top

答案4

我会在我的 .zshrc (或其他)中附加这样的片段:

if pgrep -u $USER 程序名
然后
    执行程序名

警告 :我还没有测试过这段代码。请不要在 root 或服务器上唯一的用户上使用它。确保失败时可以恢复。

相关内容