스크립트 내의 하위 쉘에서 실행될 때 "작업"이 항상 완료된 프로세스에 대한 줄을 반환하는 이유는 무엇입니까?

스크립트 내의 하위 쉘에서 실행될 때 "작업"이 항상 완료된 프로세스에 대한 줄을 반환하는 이유는 무엇입니까?

일반적으로 작업이 백그라운드에서 시작되면 jobs작업이 완료된 후 처음 실행하면 완료가 보고되지만 후속 실행에서는 아무 것도 보고되지 않습니다.

$ ping -c 4 localhost &>/dev/null &
[1] 9666
$ jobs
[1]+  Running                 ping -c 4 localhost &> /dev/null &
$ jobs
[1]+  Done                    ping -c 4 localhost &> /dev/null
$ jobs  ## returns nothing
$ 

그러나 스크립트 내의 하위 쉘에서 실행하면 항상 값을 반환하는 것 같습니다. 스크립트는 종료되지 않습니다.

#!/usr/bin/env bash
ping -c 3 localhost &>/dev/null &
while [[ -n $(jobs) ]]; do
    sleep 1; 
done

출력을 보기 위해 생성자 tee에서 사용 하면 항상 해당 행이 인쇄되는 것을 볼 수 있습니다 . 예상했던 대로 한 번이 아니라 영원히 그럴 것 같았습니다.[[ ]]jobsDone ...

낯선 사람이라도 jobs루프 내에서 실행하면 예상대로 종료됩니다.

#!/usr/bin/env bash
ping -c 3 localhost &>/dev/null &
while [[ -n $(jobs) ]]; do
    jobs
    sleep 1; 
done

마지막으로 @mury가 지적했듯이 첫 번째 스크립트는 예상대로 작동하고 명령줄에서 실행하면 종료됩니다.

$ ping -c 5 localhost &>/dev/null & 
[1] 13703
$ while [[ -n $(jobs) ]]; do echo -n . ; sleep 1; done
...[1]+  Done                    ping -c 5 localhost &> /dev/null
$ 

질문에 답변을 하던 중 이런 말이 나왔습니다.질문슈퍼유저에 관해서는 해당 루프를 수행하는 더 나은 방법을 제안하는 답변을 게시하지 마십시오. 나 자신도 몇 가지를 생각할 수 있습니다. 제가 궁금한 점은

  1. 건설 jobs과정에서 왜 다르게 행동합니까 [[ ]]? 항상 해당 Done...행을 반환하지만 수동으로 실행할 때는 반환하지 않는 이유는 무엇입니까?

  2. jobs루프 내에서 실행하면 스크립트 동작이 변경되는 이유는 무엇 입니까?

답변1

물론 이로 $(…)인해 대괄호 안의 명령이 하위 쉘에서 실행된다는 것을 알고 있습니다. 물론 이것이 jobs쉘 내장 함수라는 것을 알고 있습니다. 글쎄, jobs쉘이 죽으면 메모리에서 작업이 지워지는 것처럼 보입니다.보고되었습니다. 그러나 실행하면 $(jobs)명령 이 하위 셸에서 실행되므로 상위 셸(스크립트를 실행하는 셸) 에 백그라운드 작업(예제에서는)이 종료되었음을 jobs알릴 기회가 없습니다. ping보고되었습니다. 따라서 쉘이 thingie 를 실행하기 위해 서브쉘을 생성할 때마다 $(jobs)해당 서브쉘에는 여전히 전체 작업 목록이 있습니다(즉, ping작업은 5번째 반복 이후에 종료되더라도 거기에 있습니다) jobs. ping작업 상태를 보고합니다 (지난 4초 동안 중지된 경우에도 마찬가지).

이는 jobs루프에서 순수 명령을 실행하면 예상대로 종료되는 이유를 설명합니다.jobs 부모 쉘에서, 상위 쉘은 작업 종료에 대해 알고 있습니다.보고되었습니다사용자에게.

대화형 셸에서 왜 다른가요? 왜냐하면 대화형 셸의 전경 하위 프로세스가 종료될 때마다 셸은 전경 프로세스가 실행되는 동안 종료된 모든 백그라운드 작업을 보고하기 때문입니다1 . 따라서 실행 ping중에 종료되며 sleep 1, sleep종료되면 쉘은 백그라운드 작업이 종료되었음을 보고합니다. 기다려 보세요.


1 더 정확한 설명은 "포그라운드 프로세스가 실행되는 동안 상태가 변경된 백그라운드 작업"일 수 있습니다. 일시 중지된 작업( kill -SUSP, Ctrl프로그래밍 방식으로 + 에 해당 Z) 또는 일시 중지되지 않은 작업( 이 명령이 수행하는 작업) kill -CONT을 보고할 수도 있다고 생각합니다.fg

관련 정보