백그라운드 프로세스가 쉘 스크립트 실행 순서를 혼동함

백그라운드 프로세스가 쉘 스크립트 실행 순서를 혼동함

누군가 이 스크립트의 이유를 설명할 수 있나요?

echo one && 
echo two & 
echo three && 
echo four

나에게주세요

[1] 3692
three
four
one
two
[1]+  Done                    echo one && echo two

당연히 백그라운드 프로세스 이후의 모든 내용이 먼저 출력되고, 그 다음에는 백그라운드 프로세스 이전의 코드 줄이 시간순으로 인쇄됩니다. 나는 내가 쓰려고 했던 대본에서 그것을 우연히 발견했지만, 그것이 왜 그렇게 되었는지 알 수 없었습니다(비록 그 뒤에 약간의 독창성이 있을 것이라고 추측하지만).

나는 괄호를 사용하여 이것을 방지할 수 있다는 것을 발견했습니다:

echo one && 
(echo two &) 
echo three && 
echo four

주어진

one
two
three
four

그리고

echo one && 
(sleep 2 && echo two &)
echo three && 
echo four

주어진

one
three
four
two

두 번째 줄은 백그라운드에서 대기 상태이므로 첫 번째 줄이 이미 실행 중인 동안 출력됩니다.

그런데 왜 괄호가 이런 효과를 가져오는 걸까요?

추가 질문: 괄호가 배경 PID 출력을 방해하는 이유는 무엇입니까?

답변1

echo one && 
echo two & 
echo three && 
echo four

기억하세요. 이것은 다음과 같이 구문 분석됩니다.

echo one && echo two &
echo three && echo four

나는 이 echo명령이 성공했다고 가정합니다(전체 디스크의 파일로 리디렉션하는 등의 극단적인 경우에만 실패함). 따라서 이 코드 조각은 두 가지 작업을 병렬로 실행합니다. 하나는 행의 합계를 인쇄 one하고 다른 하나는 행 의 two합계를 인쇄합니다 . 합계 와 합계 의 분산은 보장되지 않으며 시스템, 셸 및 호출마다 다를 수 있습니다. 이와 같은 간단한 예를 사용하면 부하가 적은 시스템에서 재현 가능한 결과를 볼 수 있지만 이는 신뢰할 수 있는 것이 아닙니다.threefouronetwothreefour

echo one && 
(echo two &) 
echo three && 
echo four

구문 분석을 변경했습니다. 여기서는 명령만 echo two백그라운드에서 실행됩니다. 이렇게 하면 가 one먼저 출력되고 before와 마찬가지로 three항상 before가 되지만 four위치는 twoafter 어디에나 있을 수 있습니다 one.

셸은 기본 셸 프로세스에서 시작된 경우에만 백그라운드 프로세스에 대한 메시지를 인쇄하고, 하위 셸에서 시작된 경우에는 해당 메시지를 인쇄하지 않습니다. 괄호는 하위 쉘을 생성하므로 (echo two &)쉘이 메시지를 인쇄하지 않습니다. 이렇게 하면 백그라운드 프로세스가 생성되지만 백그라운드는 생성되지 않습니다.일하다.

echo one && 
(sleep 2 && echo two &)
echo three && 
echo four

이 코드 조각에서 백그라운드 작업은 출력하기 전에 2초 동안 휴면 상태입니다 two. 이로 인해 two및 이후에 출력이 있을 가능성이 매우 높습니다(실제로 보장되지는 않음) .threefour

답변2

1 부

echo one && 
echo two & 
echo three && 
echo four

이는 다음과 같이 다시 작성할 수 있습니다.

echo one && echo two & 
echo three && echo four

three처음에 and 를 얻는 이유는 단순히 and 를 인쇄하는 것보다 four서브셸에서 oneand 를 처리하고 실행하는 데 시간이 더 오래 걸리기 때문입니다 .twothreefour

이렇게 보면 더 확실하게 알 수 있어요

echo one && echo two &
sleep 1
echo three && echo four

이 경우, 당신은 one과 를 얻습니다 two. 잠시 후에 당신은 three과 를 얻습니다 four.

원래 시나리오에서는 및 가 and 의 출력 one과 혼합되지 않을 것이라는 보장이 없으며 또는 같은 단어가 삽입되는 경우에도 가능합니다.twothreefourthonreeetwfouro

2 부

echo one && 
(echo two &) 
echo three && 
echo four

이는 다음과 같이 다시 작성할 수 있습니다.

echo one && (echo two &) 
echo three && echo four

여기서 일어나는 일은 one즉시 인쇄한 다음 two서브셸에서 트리거된다는 것입니다. 그런 다음 다음 줄이 (연속적으로) 실행되어 threesum 을 생성합니다 four. 특별한 경우 서브쉘은 two출력하기 전에 인쇄할 수 있을 만큼 충분히 작고 빠릅니다. three그러나 이에 대한 보장은 없습니다.

세 번째 부분

명령문을 하위 쉘로 그룹화합니다. & 기호는 &명령문에 대해 작동하지만 이 경우 두 명령을 함께 연결하는 데 사용했으므로 &&단일 명령문으로 처리해야 합니다.

echo one; echo two어쩌면 대신 사용해야 할까요 echo one && echo two? 그들은 매우 다릅니다. 세미콜론은 ;두 명령을 구분하여 독립적으로 순차적으로 실행됩니다. 이중 앰퍼샌드는 &&두 명령을 함께 연결합니다.논리 AND, 첫 번째가 성공적으로 완료될 때까지 두 번째가 실행되지 않도록 합니다. false; echo yes, false && echo yes, 및 을 비교합니다 true && echo yes. 그런 다음 &&(논리 AND) 그리고 ||(논리적 또는).

보너스

서브쉘에는 작업 제어가 없으므로 작업 제어 알림이 손실됩니다.

관련 정보