Bash

less 停止我的腳本;為什麼會這樣以及如何避免?

  • May 22, 2020

s在目前目錄中命名了這個 Bash 腳本:

#!/bin/bash
pipe_test() {
   ( set -m; (
       $1
   ); set +m ) | 
   (
       $2
   )
}
pipe_test "$1" "$2"

如果我打電話給例如

./s yes less

腳本停止。less(如果我使用我嘗試過的任何其他尋呼機而不是, 即more和,也會發生類似的事情。)不過,我可以通過內置most的方式繼續它。fg

我希望對子shell 進行作業控制(由 啟用set -m),以便為子shell 的程序提供不同的程序組ID。

關於我的系統的資訊:

$ bashbug
...
Machine: x86_64
OS: linux-gnu
Compiler: gcc
Compilation CFLAGS: -g -O2 -fdebug-prefix-map=/build/bash-cP61jF/bash-5.0=. -fstack-protector-strong -Wformat -Werror=format->
uname output: Linux jarnos-OptiPlex-745 5.4.0-29-generic #33-Ubuntu SMP Wed Apr 29 14:32:27 UTC 2020 x86_64 x86_64 x86_64 GNU>
Machine Type: x86_64-pc-linux-gnu

Bash Version: 5.0
Patch Level: 16
Release Status: release
$ less --version
less version: 551

發生這種情況的原因是,啟用作業控制 ( set -m) 不僅帶來了程序分組,還帶來了處理“前台”和“後台”作業的機制。這個“機器”意味著每個命令在啟用作業控制時依次執行成為前台程序組。

因此,簡而言之,當該子外殼(管道的左側部分)啟用作業控制時,它實際上會從整個管道中竊取終端,直到那時才擁有它,並且在您的範例中包括該less程序,從而使其成為成為後台,因此不再允許使用終端。因此它會停止,因為less 它會繼續訪問終端。

通過發出fg,您將終端返回到整個管道,因此到less,並且一切都很好。除非您在作業控制子 shell 中執行其他命令,因為在這種情況下,每個附加命令都會再次竊取終端。

解決它的一種方法是在後台簡單地執行您的作業控制的子子外殼:

( set -m; (
       $1
   ) & set +m ) | 
   (
       $2
   )

您將根據需要$1在其不同的程序組中執行由 run 表示的命令,而後台模式可防止竊取終端,從而將其留給管道,從而留給$2.

自然地,這要求 in 中的命令$1不想讀取終端本身,否則它將是一旦嘗試執行該命令就會停止的命令。

此外,就像我上面所說的那樣,您可能想要添加的任何額外的作業控制子子外殼都需要相同的“背景”處理,直到您set +m,否則每個額外的作業控制子子外殼將再次竊取終端。

也就是說,如果您只需要程序分組來殺死程序,您可能會考慮使用pkill來定位它們。例如,將向其父程序是指定 PIDpkill -P的程序發送信號。這樣,您只需知道子程序的 PID,就可以針對子程序的所有子程序(但不是孫子程序)。

引用自:https://unix.stackexchange.com/questions/587526