我写了一个小 bash 脚本,显示了屏幕截图菜单 ( screenshot-menu.bash
):
#!/usr/bin/env bash
echo 'Select an option:
s whole screen
w active window
r select region
'
read -rsn1 key
sleep 0.1
case $key in
s|w|r) nohup ./screenshot.bash -$key & ;;
*) echo Canceled. >> ./log.txt ;;
esac
该脚本nohup ./screenshot.bash
使用参数运行。这是screenshot.bash
:
#!/usr/bin/env bash
while [[ "$#" > 0 ]]; do case $1 in
-s|--screen) PARAM=''; TYPE='Screen'; shift;;
-w|--window) PARAM='-u'; TYPE='Window'; shift;;
-r|--region) PARAM='-s'; TYPE='Region'; shift;;
*) echo "Unknown parameter passed: $1"; exit 1; shift; shift;;
esac; done
sleep 0.2
scrot $PARAM $(xdg-user-dir PICTURES)/'%Y-%m-%d %H.%M.%S $wx$h '$TYPE.png -e 'echo "$f" && notify-send -u low "$f"'
当我./screenshot-menu.bash
在终端内运行,然后输入 时r
,一切正常:我可以选择一个区域并获得该区域的屏幕截图。
但我希望能够从任何地方调用这个脚本。这就是为什么我有一个键绑定在新的终端窗口中运行此脚本:
alacritty -t "Screenshot menu" -o "window.dimensions.columns=20" -o "window.dimensions.lines=7" -e ~/bin/screenshot-menu.bash
(或更简单gnome-terminal -- ~/bin/screenshot.bash
。)
这就是我使用nohup
.我希望终端退出,因为我不想将其出现在屏幕截图中。但当然screenshot.bash
不能死。
第二种方法(在新终端窗口中编写脚本)可能五次有效一次。其他时候,光标不会变成十字线来选择区域。我想,screenshot.bash
虽然我用了,但还是死了nohup
。
是什么导致了这种随机行为?
答案1
问题很可能是在后台screenshot-menu.bash
执行的进程 fork 收到 a并在运行之前退出。nohup ./screenshot.bash -$key
SIGHUP
nohup
一个简单的实验似乎证实了这一点:
$ alacritty -e sh -c 'nohup sleep 1000 &'
$ pgrep -a sleep
$
strace
整个命令显示分叉,但在分叉进程收到一个(当终止并且它创建的伪终端消失时)并退出之前sh
没有execve
运行。nohup
SIGHUP
alacritty
在不寻找替代方法(在混合终端和图形应用程序时可能存在)的情况下,合理的解决方案是避免应用于nohup
将进入后台的命令,而是在父进程上使用它。例如:
$ alacritty -e sh -c 'nohup sh -c "sleep 1000 &"'
$ pgrep -a sleep
625910 sleep 1000
你screenshot-menu.bash
可以因此改变这条线
s|w|r) nohup ./screenshot.bash -$key & ;;
进入
s|w|r) nohup sh -c "./screenshot.bash \"-$key\" &" ;;
或者,您可以在screenshot-menu.bash
with中启用作业控制set -m
并删除nohup
(然后 shell 将在其自己的进程组中启动后台管道(一个简单的命令也是管道),并且只有前台进程组在SIGHUP
其控制终端时才会被传递)消失),前提是您可以确保没有任何内容screenshot.bash
尝试从终端读取或写入终端(即您需要与 执行的操作等效的显式重定向nohup
)。
例如,screenshot-menu.bash
可能会变成:
#!/usr/bin/env bash
set -m
echo 'Select an option:
...
'
case $key in
s|w|r) </dev/null >>./log.txt 2>&1 ./screenshot.bash "-$key" & ;;
*) echo Canceled. >>./log.txt ;;
esac
也可以看看:
- 进程在后台启动之前被终止- 一个非常相似的问题;答案中有更多的解释和有趣的解决方案;
- 使用 & 和输出重定向代替 nohup 安全吗?- 关于我基于工作控制的替代方案如何不等同于
nohup
。