我的 i3 配置中有这一行:
bindsym $Super+Shift+F10 exec --no-startup-id ps aux | grep -q '[p]icom' && killall picom || picom
当按下按键绑定时,它会运行 shell 命令(--no-startup-id 之后的所有内容都是 shell 命令)。 shell 命令成功地让我在桌面上使用 picom 切换合成。它运行一个命令,使用 ps 获取所有进程的列表,并使用 grep 在其中搜索“picom”。如果 grep 找到某些东西,它会返回 true,然后 Killall 将杀死所有正在运行的 picom。如果 grep 没有找到任何内容,它将启动 piccom。
但问题是,命令中有“picom”,甚至两次,所以 grep 应该总是看到它并返回 true,因此,命令应该总是运行killall picom
,对吧?
为了查看情况是否如此,我修改了命令以添加 tee 以将 ps 的输出记录在名为 log1 的文件中:
bindsym $Super+Shift+F10 exec --no-startup-id ps aux | tee log1 | grep -q '[p]icom' && killall picom || picom
cat log1 | grep picom
使用上面的 i3 键绑定后,当没有 picom 运行时的输出:
ordici 19951 0.0 0.0 3192 2040 ? Ss 17:24 0:00 /bin/sh -c ps aux | tee log1 | grep -q '[p]icom' && killall picom || picom
所以我是对的,即使 picom 没有运行, ps 的输出也包含 picom 。那么为什么该命令可以完美运行呢?
更奇怪的是,当从终端而不是 i3 键绑定运行该命令并且 picom 未运行时, ps 的日志中没有我的命令。然而该命令仍然有效,正如我所期望的那样。
答案1
通过写下这个问题,我意识到它为什么有效。我想无论如何我都会发布它,所以我不会白写这篇文章。
grep picom
在我的场景中,剂量总是返回 true,正如我所预期的那样。所以,它总是运行killall picom
。就好像命令如下(这是我从现在开始将使用的命令):
killall picom || picom
它起作用的原因是它killall
也有退出价值!当killall
没有找到任何名为“picom”的进程来杀死时,它返回一个非零退出值。这反过来会触发 picom 在失败之前按照命令运行!
因此,两者grep
或killall
失败都可以触发picom
在我的原始命令中运行。这是 if 语句和“&& ||”等逻辑运算符之间的区别。逻辑运算符使得 AND 运算符 ( ) 链中的多个命令&&
失败将触发 OR 运算符 ( ||
)。
我把原来的命令改成了if语句作为测试:
if ps aux | grep -q '[p]icom'; then
killall picom
else
picom
fi
并且该命令无法按预期切换,因为或是否执行的picom
唯一决定因素是 的返回值,并且在这种情况下始终返回 true。killall
picom
grep
grep
答案2
为什么要费心ps
和grep
-ing for picom
ifkillall
如果它不运行就会默默地失败?看来你可以这样做:
killall picom || picom
至于对命令结果(退出状态)的多个条件测试,如下:
grep -q '[p]icom' && { killall picom; true; } || picom
是您需要在不使用 if-else 的情况下执行此操作的方法,因为正如您现在发现的那样,a && b || c
这不是三元运算符,即这并不意味着:
if a; then
b
else
c
fi
它的意思是(es
=退出状态):
a; es=$?
if (( es == 0 )); then
b; es=$?
fi
if (( es != 0 )); then
c; es=$?
fi
(exit $es)
看bash if 语句与条件执行逻辑相关答案可能有助于使上述内容更加清晰。