배쉬, 일부 백그라운드 프로세스를 실행하고 다른 프로세스를 기다리는 방법은 무엇입니까?


11

나는 (아직) 다른이 wait, &, &&제어 흐름 질문을 ..

가능한 한 많은 작업을 동시에하고 싶은 스크립트가 있다고 가정 해 보겠습니다.

# may take some hours
something InputA > IrrelevantA &
something InputB > IrrelevantB &

# may take an hour
(
   somethingElse InputA > OutputA &
   somethingElse InputB > OutputB &
)&& combine OutputA OutputB > Result

...morestuff

질문 1 : 스크립트에서 두 프로세스가 계속되는 동안 두 프로세스 가 완료 될 combine때까지 기다 립니까?somethingElsesomething

질문 2 : 위의 프로세스가 백그라운드에서 계속 진행 되는 동안 combinesomethingElse프로세스 만 기다리 려면 어떻게해야 something합니까?

답변:


13

예제에서 combine서브 쉘이 종료 되 자마자 명령이 실행됩니다 (그리고 마지막 백그라운드 프로세스가 오류없이 시작된 경우). wait명령 이 없으므로 작업이 시작된 직후 서브 쉘이 종료됩니다 .

두 개 이상의 동시 백그라운드 프로세스의 반환 값을 기반으로 명령을 실행하려면 반환 값으로 임시 파일을 사용하는 것 외에 다른 방법을 볼 수 없습니다. 대기중인 프로세스 중 하나wait리턴 값 만 리턴 할 수 있기 때문 입니다. 또한 백그라운드 프로세스는 리턴 값을 얻기 위해 서브 쉘에서 실행되어야하므로 변수에 저장할 수 없습니다. 당신은 할 수 있습니다 :

something InputA >IrrelevantA &
something InputB >IrrelevantB &

tmp1=$(mktemp)
tmp2=$(mktemp)

( somethingElse InputA >OutputA; echo $? >"$tmp1" ) &
proc1=$!

( somethingElse InputB >OutputB; echo $? >"$tmp2" ) &
proc2=$!

wait "$proc1" "$proc2"

read ret1 <"$tmp1"
read ret2 <"$tmp2"
[ "$ret1" = 0 && "ret2" = 0 ] && combine OutputA OutputB >Result

rm "$tmp1" "$tmp2"

실제로 반환 값에 신경 쓰지 않으면 작업을 정상적으로 시작하고 다음을 사용할 수 있습니다 wait.

something InputA >IrrelevantA &
something InputB >IrrelevantB &

somethingElse InputA >OutputA &
proc1=$!

somethingElse InputB >OutputB &
proc2=$!

wait "$proc1" "$proc2"
combine OutputA OutputB >Result

안녕하세요, 제 2 옵션이 저에게 효과적이라고 생각합니다.
Stephen Henderson

3

겠습니까 프로세스 대체 당신이 파일을 저장할 필요가 없습니다 특히,보다 효율적으로 OutputA하고 OutputB, 단지에 대한 관심 Result? 특히 시간을 절약 할 파일을 저장, 당신은 디스크에 서면으로 느린 I / O가있는 경우 때문에겠습니까 OutputAOutputB속도 제한 단계가 될 수 있는가?

combine  <(somethingElse InputA)  <(somethingElse InputB)  >  Result

프로세스 대체를 사용하면 <(..here..)출력을 파일에 저장 한 다음 "combine"단계에서 입력으로 읽는 대신 명령을 내부에 넣을 수 있습니다 .

메모리 제한, 그리고 크기 인 경우 outputAoutputB더 많은 메모리에 저장할 수있는 것보다를, 그것은 전체 목적을 물리 칠 것인가?

combine두 프로세스가 모두 완료 될 때까지 기다렸다가 실행을 시작합니까?


이것은 "Jeopardy"가 아닙니다. 질문의 형태로 답장을 보내지 마십시오 . 진심으로, 당신은 새로운 아이디어를 생각해 냈고, 나는 그것이 꽤 좋다고 생각합니다. 두 가지 요점에 응답하려면 combinesomethingElse명령이 시작 되 자마자 실행되기 시작하지만 문제는 문제 <(…)가되지 않습니다. 따라서 프로세스 combine를 초과하면 데이터를 기다리게 somethingElse됩니다. 그리고 파이프이기 때문에 크기는 문제가되지 않습니다. … (계속)
G-Man, 'Reinstate

(계속)… 귀하의 답변에 대한 유일한 실질적인 문제는 somethingElse프로세스 의 종료 상태를 테스트 할 수 없다는 것입니다. 그리고 이것이 asker에게 중요한지 확실하지 않습니다. 그러나 대답이 그런 질문을해서는 안됩니다.
G-Man, 'Reinstate

2

다음 wait명령을 사용할 수 있습니다 .

(echo starting & sleep 10 & wait) && echo done

"시작"줄이 바로 나타나는 것을 볼 수 있으며 "완료"는 10 초 동안 기다립니다.


일반적으로 대기에는 동일한 쉘의 하위 프로세스가 필요합니다. 거기는 꽤 까다 롭습니다.
mikeserv

1
@ mikeserv, 무슨 소리 야? 그것은 요점입니다. 그것은 그 서브 쉘에있는 모든 아이들을 기다립니다.
psusi

내 초기 테스트에 의해 작동합니다. 나는 지금 큰 스크립트에서 시도 할 것입니다
Stephen Henderson

정확히-동일한 쉘의 하위 - 하위 쉘. 이스케이프를 시도하지 않는 프로세스 또는 데몬 리 제이션 또는 그 밖의 모든 프로세스에서 작동합니다. 프로세스 리더가 괜찮다고 기다리는 한 프로세스가 자체 프로세스 리더가 되려고 시도하면 대기하는 데 문제가 있습니다.
mikeserv

0

사실 이런 종류의 다른 대답 할 수있는 방법을 정확하게 보여 여기 . 그 대답은 백그라운드 프로세스로 2 개의 로그를 유지 관리하는 것에 관한 질문에 대한 것이므로 10으로 표시했습니다.

데모 스크립트

cat <<-\DEMO >|${s=/tmp/script} 
printf 'tty is %s\nparent pid is %s\npid is pid=%s\n' \
     "$(tty)" "$PPID" "$$"
exec 1>&2 ; nums=$(seq 0 9)
rm ${files=$(printf "/tmp/file%s\n" $nums)}
for n in $nums ; do { for f in $files ; do
    echo "Line $n" >>"$f" ; done
sleep 1 ; } ; done
#END
DEMO

데모 실행

s=/tmp/script ;chmod +x $s ;info="$(($s &)2>&- &)"
echo "$info" ; pid="${info##*=}" ; echo
while ps -p $pid >/dev/null ; do sleep 3 ; done
for f in /tmp/file[0-9] ; do
    printf 'path : %s\tline count : %s\n' \
        $f $(<$f wc -l)
done

산출:

tty is not a tty
parent pid is 1
pid is 12123

path : /tmp/file0    line count : 10
path : /tmp/file1    line count : 10
path : /tmp/file2    line count : 10
path : /tmp/file3    line count : 10
path : /tmp/file4    line count : 10
path : /tmp/file5    line count : 10
path : /tmp/file6    line count : 10
path : /tmp/file7    line count : 10
path : /tmp/file8    line count : 10
path : /tmp/file9    line count : 10

이상이 설명합니다. 그것은 구축하고라는 이름의 스크립트가 실행 /tmp/script, chmod 실행 파일로하고, 그것을 실행 &background&backgrounded ( subshell ).

스크립트는 rms /tmp/file0-910 개의 파일과 10 개의 echoes줄을 1 초마다 한 줄씩 만듭니다. 사용하지 않는 $info프로세스에서 일부 를 캡처하여 캡처 $(command substitution). While ps에 대한 스틸 보고서를 통해 표시 $pid합니다. 여전히 실행되고 있다는 것을 알고 sleep.있습니다. 완료되면 10 개 파일의 행이 모두 계산됩니다.wc.

이러한 방식으로 프로세스를 호출 한 후에는 원래 상위 프로세스를 자유롭게 닫을 수 있으며 계속 트럭 킹을 계속할 수 있습니다. 이것은 또한 일반적인 wait명령을 사용할 수는 없지만 ps 반환 대기는 더 강력해야합니다.

언급 할만큼 가치, 내가 생각하는 과정이 실제로 처음에 호출 될 것입니다 $(command substitution)그리고 printfs나는 $info내가 효과적으로 제어 할 수 있도록 내가 할 수 있습니다. 하지만 그것의 출력 단자를 삭제 자마자 exec 1>&2(어느 것이 서브 쉘과 같은 폐쇄되고 2>&-), 처리는 탈출 I의 타단에 대해 주위를 기다려야한다. 모든 경로 재 지정 및 프로세스 리더에 대해 마음을 감쌀 수있는 한, 특히 파이프를 사용하여 입력 파이프를 처리하는 경우 두 가지 이점을 모두 활용하십시오.

다른 모든 것들은 여기서 시연하기위한 것입니다. 이 스크립트를 실행하기 위해 필요한 것은 다음과 같습니다.

info="$(($script_path &)2>&- &)"    

참고 : 이것은 내가 보여주고 싶었던 것과 정확하게 터미널에만 인쇄합니다. $PPID,이 프로세스에서언급했듯이이 프로세스는 터미널에서 제외되며$PID 1.

이 두 가지를 동시에 실행하고 기다리려면 ps두 pid를 모두주고 기다릴 수 있습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.