为什么我不能在 bash 脚本上将 pgrep 输出正确地输出到变量?

Tub*_*ube 5 bash stdout stderr pgrep exit-status

我正在尝试制作一个脚本,要么在 compton 正在运行时退出它,要么在它没有运行时启动它。我从 man 那里读到如果找到进程它应该退出 1,所以我试图制作一个使用它的脚本......但是这不起作用,如果它关闭但不关闭它就会启动. 我究竟做错了什么 ??

#!/bin/bash


status=$(pgrep compton 2>&1)

if [[ $status == 1 ]];
    then
        killall compton
    else
        exec compton -b
fi

echo $status
Run Code Online (Sandbox Code Playgroud)

Kus*_*nda 8

正在变量获取pgrep输出status。这不是您期望的输出。

pgrep输出与您提供的模式匹配的进程的进程 ID (PID)。如果存在名称匹配的进程compton$status则将是该进程或这些进程的 PID。 pgrep也返回退出状态,但退出状态不会被命令替换作为字符串捕获。

在您的测试中,您将$status1. comptonPID 为 1 的可能性不大。


如果你想杀死任何compton存在的进程,并compton -b在没有compton进程存在时启动,你可以这样做

#!/bin/sh

if ! pkill compton; then
    exec compton -b
fi
Run Code Online (Sandbox Code Playgroud)

这使用 的退出状态pkill。该pkill工具的工作原理以等效的方式来pgrep(它们通常被分布和安装为一对),但不输出匹配处理的PID等pgrep会做,pkill发送TERM信号(默认)到匹配过程。

if关键字使用与其一起使用的命令的退出状态。

!反转测试的意义,使

  • 如果pkill compton成功,就意味着有一个或几个compton现在已被打死,或者至少暗示,和过程exec compton -b将不会被执行。

  • 如果pkill compton失败(没有与名称匹配的进程,或者 中存在一些内部错误pkill),则if语句的主体将调用 your exec compton -b,它将用运行产生的进程替换 shell 进程compton -b


Jak*_*dra 6

您应该控制 pgrep 进程的退出状态,该状态将在 $? 多变的。或者检查存储 pgrep 输出的 $status 变量是否为非零长度字符串。问题中的脚本检查变量状态中的字符串是否为“1”

所以

#!/bin/bash
pgrep compton >/dev/null

if [[ $? -eq 0 ]]
then
    killall compton
else
    exec compton -b
fi
Run Code Online (Sandbox Code Playgroud)

或者

#!/bin/bash
status=$(pgrep compton 2>&1)

if [[ -n "$status" ]]
then
    killall compton
else
    exec compton -b
fi
Run Code Online (Sandbox Code Playgroud)

  • `如果 pgrep 康普顿 >/dev/null; then` 是更好的做法,所以根本不直接检查 `$?`。除了避免“$?”所指的命令与您在编辑代码以添加日志记录等时认为的命令不同的错误之外,这也意味着“set -e”将不再将“pgrep”返回 1 作为原因退出脚本(因为在其退出状态上进行分支将其标记为“已检查”)。 (3认同)
  • @adamlogan 这就是重点。您不需要将退出状态存储在变量中并在条件中比较变量。您可以使用命令作为条件,其工作方式相同。`如果命令; 然后…… ;fi` 或 `if ! 命令; 然后 … ; 菲` (2认同)