다른 터미널에서 스크립트를 제어한 후 Ctrl-C를 누를 수 없습니다

다른 터미널에서 스크립트를 제어한 후 Ctrl-C를 누를 수 없습니다

나는 blah.sh이것을 터미널에서 실행하고 있습니다. 그런 다음 다른 터미널에서 일시 중지하고 나중에 다시 시작하는 스크립트를 실행하고 있습니다 blah.sh.

...

script_id=`pidof -x blah.sh`
kill -s SIGSTOP $script_id

...

script_id=`pidof -x blah.sh`
kill -s SIGCONT $script_id

그 후에 는 백그라운드로 푸시됩니다. 이를 중지 하려면 - 를 입력 blah.sh해야 합니다 .fgCtrlC

blah.sh전송 후 터미널의 전경에 자동으로 표시하는 방법이 있습니까 SIGCONT?

답변1

blah.sh전송 후 터미널의 전경에 자동으로 표시하는 방법이 있습니까 SIGCONT?

먼저 필요한 것이 무엇인지에 따라 SIGSTOP원하는 것을 얻을 수도 있고 얻지 못할 수도 있습니다.


분석하다

귀하의 경우에는 다음과 같은 일이 일어나고 있다고 생각합니다.

  1. 작업 제어는 실행하는 셸에서 활성화됩니다 blah.sh. 쉘은 별도의 프로세스 그룹에서 프로세스를 시작하고 프로세스 그룹이 이제 포그라운드 프로세스 그룹임을 터미널에 알립니다. 이런 방식으로 프로세스가 전경에서 실행되는 동안 쉘은 자신을 배경에 둡니다.

  2. 프로세스를 실행 하면 kill -s STOP(다른 터미널에 입력하여) 프로세스가 중지되고 쉘이 SIGCHLD자동으로 시작됩니다. 이 신호는 '당신의 자녀 중 적어도 한 명은 차단되거나 종료되었습니다. 이제 자녀를 확인하고 대응해야 할 때입니다.'라는 의미입니다.

  3. 쉘은 반응하여 SIGCHLD하위 프로세스가 중지된 것을 확인하고 자신의 프로세스 그룹을 터미널의 전경 프로세스 그룹으로 설정하여 자신을 전경으로 가져옵니다. 보내는 대신 보내는 경우 SIGTSTP이는 쉘을 전경으로 가져오는 정확한 메커니즘입니다 SIGSTOP. 예를 들어, 프로세스가 실행 중인 터미널에서 +를 누르면 Ctrl포그라운드 프로세스 그룹이 수신하게 됩니다. 이는 쉘이 반응하도록 하는 것이 아니라 프로세스를 의미합니다.ZSIGTSTPSIGCHLD

  4. 이제 쉘이 포그라운드에 있으며 프롬프트를 인쇄하고 입력을 기다리고 있습니다.

  5. 실행 하면 프로세스가 계속됩니다 kill -s CONT. SIGCHLD쉘이 반응하도록 하는 유사한 메커니즘은 없습니다 . 쉘은 터미널의 전경 프로세스 그룹을 모르고 변경하지 않습니다. 실제로 쉘은 여전히 ​​공식적으로 포그라운드에 있고 프로세스는 여전히 공식적으로 백그라운드에 있습니다.

프롬프트를 무시하고 쉘과의 상호작용을 중단하는 것만으로도 충분하다고 생각할 수도 있습니다. 일반적으로 말하자면: 아니요. 백그라운드 프로세스가 SIGTTIN터미널(대개 표준 입력)에서 읽기를 시도하면 메시지를 받게 됩니다. 터미널( )의 설정에 따라 stty tostop백그라운드 프로세스가 SIGTTOU터미널(대부분 stdout 및 stderr)에 쓰기를 시도하면 이를 수신할 수도 있고 수신하지 못할 수도 있습니다. SIGTTIN또는 의 기본 작업은 SIGTTOU프로세스를 중지하는 것입니다. 또한 읽기를 시도하는 동안 프로세스가 중지되지 않더라도 쉘은 여전히 ​​동일한 터미널에서 읽고 있으므로 쉘이 입력을 "훔치기" 때문에 프로세스와 상호 작용하기가 어렵습니다.

Ctrl+ 터미널 드라이버를 포그라운드 프로세스 그룹으로 C보낼 수 있도록 합니다 . SIGINT문제의 프로세스가 백그라운드에 있으면 신호를 받을 수 없습니다.

입력 ( 다른 터미널에서 전송하는 fg대신 )은 쉘에 내장되어 있으므로 실제로 이를 처리하는 쉘이기 때문에 잘 작동합니다 . 이제 쉘은 프로세스를 전면으로 가져오려는 것을 알고 자체 동작을 변경합니다. (터미널 읽기에서 프로세스를 중지하고) 프로세스의 프로세스 그룹으로 보내기 전에 이에 따라 전경 프로세스 그룹을 설정합니다.SIGCONTfgfgSIGCONT

프로세스를 중지한 이유가 셸과 상호 작용하기 위한 것이라면 셸과 상호 작용(즉, 셸 호출)하여 프로세스를 재개해야 합니다 fg.


가능한 해결책

하지만만약에프로세스를 중지한 이유는 셸과 관련이 없습니다(예: 프로세스가 컴퓨팅을 중지하기를 원하는 경우). 프로세스를 시작하는 방식을 변경해야 합니다. 셸에서 작업 제어 비활성화. 다음과 같은 일이 일어날 것입니다:

  1. 당신은 실행합니다 set +m; blah.sh. set +m작업 제어를 비활성화합니다. 쉘이 시작되면 blah.sh프로세스가 쉘의 프로세스 그룹에 배치됩니다. 이 프로세스 그룹은 앞으로도 항상 포그라운드 프로세스 그룹이 될 것입니다.

  2. 프로세스를 실행 하면 kill -s STOP(다른 터미널에 입력하여) 프로세스가 중지되고 쉘이 SIGCHLD자동으로 시작됩니다.

  3. 쉘 쌍이 반응합니다 SIGCHLD. 하위 프로세스가 종료되었는지, 사용자와의 상호 작용을 재개할 시간인지 알고 싶어합니다. 쉘은 하위 프로세스가 종료되지 않고 중지된 것으로 보고 작업 제어가 비활성화되어 있으므로 이러한 경우 쉘은 사용자와의 상호 작용을 재개하지 않습니다.

  4. 쉘과 프로세스가 모두 포그라운드에 있습니다. 쉘은 읽기 또는 쓰기를 시도하지 않으며 프로세스가 중지됩니다. 그들은 단지 거기에 머물러 있습니다.

  5. 실행 하면 프로세스가 계속 진행됩니다 kill -s CONT. 쉘은 모르지만 프로세스가 결국 종료될 때까지 기다리고 다른 할 일이 없기 때문에 중요하지 않습니다.


노트

  • blah.sh기술적으로 이 솔루션은 " 터미널에서 자동으로 전경을 표시하는 방법" 이 아닙니다 . blah.sh항상 전경에 있으므로 "자동 전경"할 필요가 없습니다.

  • 항상 전경에 있기 때문에 blah.sh해당 시점에 중지되어도 Ctrl+ C가 전송됩니다 . SIGTERMStopped는 수신된 경우 blah.sh에만 반응합니다 . 단독으로 보내는 것은 하위 항목으로 보내는 것을 의미하지 않으며 + 즉시 반응 할 가능성이 높습니다 .SIGTERMSIGCONTSIGSTOPblah.shSIGSTOPCtrlC

  • SIGSTOP단독으로 보내는 것이 하위 항목으로 blah.sh보내는 것을 의미하지 않으므로 전체 프로세스 그룹이 상주하는 프로세스 그룹 으로 보내는 것을 고려할 수 있습니다. 어떤 이유로든 의도적으로 다른 프로세스 그룹에 포함되지 않는 한 각 하위 항목도 해당 그룹에 속하게 됩니다. "음수 PID 값을 사용하여 전체 프로세스 그룹을 선택할 수 있습니다"라는 부분을 참조하세요 .SIGSTOPSIGSTOPSIGCONTblah.shman 1 kill

    일반적으로(셸에서 작업 제어가 활성화된 경우) 해당 blah.sh하위 항목이 PID와 동일한 PGID를 가진 프로세스 그룹에 있을 것으로 예상해야 합니다 blah.sh. 우리 솔루션에서는(작업 제어가 비활성화된 경우) 해당 하위 항목이 셸과 동일한 프로세스 그룹에 있을 것으로 예상해야 하며 blah.shPGID는 셸의 PID와 같을 수도 있고 같지 않을 수도 있습니다.

  • set +m; blah.sh; set -m종료 후 작업 제어를 자동으로 다시 활성화하려는 경우 blah.sh유망해 보이지만 Ctrl실행 중에 +를 사용하여 이를 중단하면 작동하지 않습니다. 이 상황을 안정적으로 처리할 수 있는 몇 가지 함정이 있지만 자세히 설명하지는 않겠습니다.Cblah.shset -m

  • 작업 제어가 비활성화되면 쉘은 이를 무시합니다 SIGTSTP. 쉘에 의해 시작된 프로세스(예: blah.sh)도 이를 무시합니다. (일부 프로세스가 의도적으로 무시하지 않도록 선택하지 않는 한) 이는 Ctrl+가 작동할 것이라고 기대해서는 안 된다는 의미입니다 Z.

답변2

이를 수행할 방법이 없습니다. 쉘만이 포그라운드 애플리케이션을 관리할 수 있습니다. 쉘에 백그라운드에서 실행 중인 여러 애플리케이션이 있고 SIGCONT다른 터미널에서 그 중 여러 애플리케이션으로 전송하는 상황을 생각해 보세요. 무슨 일이 일어날 것으로 예상합니까?

유일한 목적이 단계를 제거하는 것이라면 먼저 실행 kill -s SIGCONT $script_id한 다음 실행하는 대신 단계를 실행하면 됩니다. 이미 백그라운드 프로세스로 전송되었으므로 명령을 사용하여 신호를 명시적으로 보낼 필요가 없습니다.fgfgfgSIGCONTkill

관련 정보