프로그램이 완료될 때까지 기다렸다가 완료되면 stdin을 stdout으로 파이프할 수 있습니까?

프로그램이 완료될 때까지 기다렸다가 완료되면 stdin을 stdout으로 파이프할 수 있습니까?

명령이 완료될 때까지 기다린 다음 stdin을 stdout으로 파이프하는 방법을 알아내려고 합니다. 저는 Mac을 사용하고 있지만 제 질문은 Mac과 관련된 것보다 프로세스가 완료될 때까지 기다리고 출력을 파이프하는 방법에 관한 것 같습니다.

Mac에서는 여러 명령을 함께 실행할 수 있으며 연산자를 사용하여 명령을 연결하면 say다음 명령을 시작하기 전에 각 구문이 완전히 말해질 때까지 기다립니다.&&

$ say "stage 1" && say "stage 2"

이것이 실제 사용 사례입니다. bash 스크립트가 있고 stdin을 stdout으로 전달하고 싶습니다.뒤쪽에끝났습니다.

$ cat /etc/passwd | say_and_pass "stage 1" | grep -v test | say_and_pass "stage 2"

따라서 개념적으로 이것은 "Phase 1"이라고 큰 소리로 말한 다음 즉시 "Phase 2"라고 말한 다음 grep의 내용을 /etc/password표준 출력으로 덤프합니다.

스크립트의 초기 크랙은 say_and_pass다음과 같습니다.

말하고 통과

#!/usr/bin/env bash
OUT="$*"
say "$OUT" && cat 

하지만 작동하지 않는 것 같습니다 ;-)

편집: 위의 예를 say_and_pass "stage2"최종 명령으로 사용하도록 변경했습니다. 이는 필요한 것입니다.내 솔루션일하다...

답변1

이것이 실제 사용 사례입니다. 무언가를 완료한 후 stdin을 stdout에 전달하려는 bash 스크립트가 있습니다.

$ cat /etc/password | say_and_pass "stage 1" | grep -v test | say "stage 2"

여기서 수행하려는 작업의 문제점은 두 개의 데이터 스트림이 있는 것으로 보인다는 것입니다. 하나는 텍스트 say처리용이고 다른 하나는 텍스트 처리용(예: catsum grep)입니다.

데이터를 혼합하기 때문에 단일 파이프라인을 사용할 수 없습니다. cat /etc/passwd | say컴퓨터가 파일의 전체 내용을 읽으려고 시도하게 됩니다. 게다가 say쓰지 마세요 .아무것표준 출력으로 변환하므로 파이프에 더 이상 아무것도 남지 않습니다.

데이터 처리 스트림을 "중단"하여 다른 유틸리티(예 say: 임시 파일.

귀하의 데모 사례는 예제로서 그다지 도움이 되지 않습니다. 왜냐하면 says 에도 불구하고 grep파일을 핑하는 것일 뿐이므로 grep -v test /etc/passwd( cat file | grep pattern는 다음을 통해 수행할 수 있습니다.쓸모없는 사용cat).

요약하면 다음은 임시 파일을 사용하는 예입니다.

scratch=$(mktemp)
trap "rm -f $scratch" EXIT
cat /etc/passwd > $scratch
say "Stage one"
grep -v test $scratch
say "Stage two"

그 중 하나는 명명된 파이프를 사용하여 다음을 수행합니다 say.

mkfifo youtalktoomuch
say youtalktoomuch &
exec 3> youtalktoomuch
do_thing_one
echo "Stage one" > youtalktoomuch
do_thing_two
echo "Stage two" > youtalktoomuch
exec 3>&-
rm youtalktoomuch

Once again, though, if you need to connect the output of `do_thing_one` to the input of `do_thing_two` without piping one into the other, you will need to use either another named pipe or a scratch file on disk to hold the data.

답변2

이 버전의 say_and_pass기능은 OP의 요구 사항을 충족합니다.

#!/usr/bin/env bash

# Create a temporary file to store stdin
TEMP_STDIN="$(mktemp)"

# Capture stdin and save it to temporary file
cat - > "${TEMP_STDIN}"

# say message, but prevent any output to stdout
say "$@" > /dev/null

# Dump saved stdin to stdout
cat "${TEMP_STDIN}"

# Clean up, but prevent any output to stdout
rm -f "${TEMP_STDIN}" > /dev/null

grep@DopeGhoti가 제안한 것과 같은 임시 파일을 사용하지만 스크립트 외부에 다른 로직(예: )을 유지합니다 . 이로 인해 더 다양하고 재사용이 가능해졌습니다 say_and_pass.

목표/목적에 대한 나의 해석은 잠재적으로 긴 파이프라인의 진행 상황을 모니터링할 수 있는 청각적인 방법이 필요하다는 것입니다.

따라서 실행할 때:

cmd1 | say_and_pass "stage 1" | cmd2 | say_and_pass "stage 2"

사용자는 실행이 완전히 완료되었음을 소리로 알 수 있습니다 . 하지만 완료될 때까지 표준 입력 처리를 시작할 수 없다는 cmd1것이 단점입니다 . 그러나 OP는 절충안을 인식하고 이를 기꺼이 수행하려는 것 같습니다.cmd2cmd1

이는 @BradParks의 답변과 유사하지만 bash의 사용 가능한 메모리(@agc가 지적한 대로)에 의해 제한되지 않으며 실수로 stdout을 오염시키는 것을 방지하는 데 약간 더 주의합니다.

또한 메시지를 자체 변수에 캡처할 필요가 없으므로 "$@"에 전달할 수 있습니다 say.

답변3

내가 해야 할 일은 스크립트 시작 부분에서 모든 stdin을 소비하는 것뿐입니다... stdin이 수신될 때 stdin을 처리하는 것이 아니라 파이프라인 체인의 이전 명령 전체가 완료될 때 처리하기를 원합니다.

여기 내 say_and_pass스크립트가 있습니다. 내 사용 사례에 적합합니다!

#!/usr/bin/env bash

OUT=$(cat -)

MSG="$*"
say "$MSG"

echo "$OUT"

답변4

시간!

귀하의 답변에 따라 stdin을 stdout으로 덤프하고 이를 변수에 저장하는 부분을 제거하는 것이 좋습니다. 이렇게 하면 메모리 소비가 줄어들고 파이프라인 체인이 파이프라인과 같은 방식으로 작동하게 됩니다(입력 한 줄이 처리되고 결과가 다음 프로세스로 전송됨).

#!/usr/bin/env bash

MSG="$*"
say "$MSG"

cat -

관련 정보