呼叫腳本退出時,使用 nohup 呼叫的腳本有時會死掉
我寫了一個小 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
.什麼可能導致這種隨機行為?
這個問題很可能是在後台
screenshot-menu.bash
執行的程序收到 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
並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
。