"읽기"에 대한 파이프 입력이 "읽는 동안 ..."구성에 공급 될 때만 작동하는 이유는 무엇입니까?
이 질문에 이미 답변이 있습니다.
- 파이프에서 쉘 변수로 값 읽기 15 답변
다음과 같이 프로그램 출력에서 환경 변수에 대한 입력을 읽으려고했습니다.
echo first second | read A B ; echo $A-$B
결과는 다음과 같습니다.
-
A와 B는 항상 비어 있습니다. 나는 bash가 하위 셸에서 파이프 명령을 실행하고 기본적으로 입력을 읽을 수 없도록하는 것을 읽었습니다. 그러나 다음은 다음과 같습니다.
echo first second | while read A B ; do echo $A-$B ; done
작동하는 것처럼 보이며 결과는 다음과 같습니다.
first-second
누군가 여기에 논리가 무엇인지 설명해 주시겠습니까? while
... done
구조 내부의 명령 이 실제로 echo
하위 쉘이 아닌 동일한 쉘에서 실행 됩니까?
stdin 에 대해 루프를 수행 하고 변수에 결과를 저장하는 방법
아래 bash는 (그리고 다른 쉘 도), 사용하여 당신 파이프 뭔가 |
다른 명령에, 당신은 묵시적으로 만듭니다 포크 , 현재 세션의 자식이고 현재 세션의와 환경에 영향을 미칠 수없는 서브 쉘을.
그래서 이건:
TOTAL=0
printf "%s %s\n" 9 4 3 1 77 2 25 12 226 664 |
while read A B;do
((TOTAL+=A-B))
printf "%3d - %3d = %4d -> TOTAL= %4d\n" $A $B $[A-B] $TOTAL
done
echo final total: $TOTAL
예상 한 결과를 얻지 못할 것입니다! :
9 - 4 = 5 -> TOTAL= 5
3 - 1 = 2 -> TOTAL= 7
77 - 2 = 75 -> TOTAL= 82
25 - 12 = 13 -> TOTAL= 95
226 - 664 = -438 -> TOTAL= -343
echo final total: $TOTAL
final total: 0
계산 된 TOTAL 은 메인 스크립트에서 재사용 할 수 없습니다.
포크 반전
사용하여 bash는 프로세스 대체를 , 여기에 문서 또는 여기에 문자열을 , 당신은 포크를 반전 할 수 :
여기 문자열
read A B <<<"first second"
echo $A
first
echo $B
second
여기 문서
while read A B;do
echo $A-$B
C=$A-$B
done << eodoc
first second
third fourth
eodoc
first-second
third-fourth
루프 외부 :
echo : $C
: third-fourth
Here 명령
TOTAL=0
while read A B;do
((TOTAL+=A-B))
printf "%3d - %3d = %4d -> TOTAL= %4d\n" $A $B $[A-B] $TOTAL
done < <(
printf "%s %s\n" 9 4 3 1 77 2 25 12 226 664
)
9 - 4 = 5 -> TOTAL= 5
3 - 1 = 2 -> TOTAL= 7
77 - 2 = 75 -> TOTAL= 82
25 - 12 = 13 -> TOTAL= 95
226 - 664 = -438 -> TOTAL= -343
# and finally out of loop:
echo $TOTAL
-343
이제 기본 스크립트$TOTAL
에서 사용할 수 있습니다 .
명령 목록에 배관
But for working only against stdin, you may create a kind of script into the fork:
printf "%s %s\n" 9 4 3 1 77 2 25 12 226 664 | {
TOTAL=0
while read A B;do
((TOTAL+=A-B))
printf "%3d - %3d = %4d -> TOTAL= %4d\n" $A $B $[A-B] $TOTAL
done
echo "Out of the loop total:" $TOTAL
}
Will give:
9 - 4 = 5 -> TOTAL= 5
3 - 1 = 2 -> TOTAL= 7
77 - 2 = 75 -> TOTAL= 82
25 - 12 = 13 -> TOTAL= 95
226 - 664 = -438 -> TOTAL= -343
Out of the loop total: -343
Note: $TOTAL
could not be used in main script (after last right curly bracket }
).
Using lastpipe bash option
As @CharlesDuffy correctly pointed out, there is a bash option used to change this behaviour. But for this, we have to first disable job control:
shopt -s lastpipe # Set *lastpipe* option
set +m # Disabling job control
TOTAL=0
printf "%s %s\n" 9 4 3 1 77 2 25 12 226 664 |
while read A B;do
((TOTAL+=A-B))
printf "%3d - %3d = %4d -> TOTAL= %4d\n" $A $B $[A-B] $TOTAL
done
9 - 4 = 5 -> TOTAL= -338
3 - 1 = 2 -> TOTAL= -336
77 - 2 = 75 -> TOTAL= -261
25 - 12 = 13 -> TOTAL= -248
226 - 664 = -438 -> TOTAL= -686
echo final total: $TOTAL
-343
This will work, but I (personally) don't like this because this is not standard and won't help to make script readable. Also disabling job control seem expensive for accessing this behaviour.
Note: Job control is enabled by default only in interactive sessions. So set +m
is not required in normal scripts.
So forgotten set +m
in a script would create different behaviours if run in a console or if run in a script. This will not going to make this easy to understand or to debug...
First, this pipe-chain is executed:
echo first second | read A B
then
echo $A-$B
Because the read A B
is executed in a subshell, A and B are lost. If you do this:
echo first second | (read A B ; echo $A-$B)
then both read A B
and echo $A-$B
are executed in the same subshell (see manpage of bash, search for (list)
a much cleaner work-around...
read -r a b < <(echo "$first $second")
echo "$a $b"
This way, read isn't executed in a sub-shell (which would clear the variables as soon as that sub-shell has ended). Instead, the variables you want to use are echoed in a sub-shell that automatically inherits the variables from the parent shell.
What you are seeing is the separation between processes: the read
occurs in a subshell - a separate process which cannot alter the variables in the main process (where echo
commands later occur).
A pipeline (like A | B
) implicitly places each component in a sub-shell (a separate process), even for built-ins (like read
) that usually run in the context of the shell (in the same process).
"동안에 파이프"의 경우의 차이는 환상입니다. 동일한 규칙이 적용됩니다. 루프는 파이프 라인의 후반부이므로 서브 쉘에 있지만 전체 루프는 동일한 서브 쉘에 있으므로 프로세스 분리가 적용되지 않습니다.
'code' 카테고리의 다른 글
빈 C # 이벤트 처리기를 자동으로 만들기 (0) | 2020.11.06 |
---|---|
UIPopoverController는 pushViewController에서 최대 높이로 자동 크기 조정 (0) | 2020.11.06 |
copy-local은 언제 true로 설정해야하고 언제 그렇지 않아야합니까? (0) | 2020.11.05 |
C # Windows API를 통해 파일에서 축소판 가져 오기 (0) | 2020.11.05 |
Android의 카메라에서 사용하는 SurfaceView에 오버레이를 그리는 방법은 무엇입니까? (0) | 2020.11.05 |