Bash - 출력을 변수 또는 파일 설명자로 리디렉션하고 변수 또는 파일 설명자에서 읽습니다.

Bash - 출력을 변수 또는 파일 설명자로 리디렉션하고 변수 또는 파일 설명자에서 읽습니다.

다음은 모든 출력을 파일로 리디렉션하고 화면에 출력을 표시하는 bash 스크립트의 예입니다.

# writing to it
exec > >(tee --ignore-interrupts ./log)
exec 2>&1

echo "here is a message"

# reading from it again
cat ./log

이제 파일을 만들고 싶지 않습니다 ./log. 모든 stdout을 메모리에 보관하고 나중에 스크립트에서 다시 읽을 수 있기를 원합니다. 또한 루트 파일 시스템이 마운트되지 않는 상황에 처해 있습니다.

대신 프로세스 대체를 사용해 보았지만 ./log방금 작성한 내용을 읽기 위해 후속 명령에 대한 프로세스 대체에 의해 생성된 파일 설명자를 전달하는 방법을 알 수 없는 것 같습니다.

또 다른 예는 다음과 같습니다.

# can I make ./log a temporary file descriptor, an in-memory buffer?
exec 3>./log 4<./log
# writes
echo >&3 "hello"
# reads
cat <&4

답변1

작성된 모든 내용을 전역적으로 리디렉션하려는 경우(지금처럼) 까다롭지만 함께 정리할 수 있습니다.

가능하다면 일반 파이프를 사용하는 것이 좋습니다. 서브셸에서 수행하는 모든 작업을 감싸면 됩니다. 이 경우

(
 echo "this is the message"
 other stuff
) | cat

아니면 그냥 "$()" 구문을 사용하여 모든 것을 변수에 씁니다.

다음 방법은 당신이 한 것을 사용하고 tmpfs에 쓰거나 /dev/shm사용 가능한 경우에 쓰는 것입니다. 매우 간단하지만 어떤 램 기반 파일 시스템이 있는지 알아야 합니다(그리고 가능하다면 설정해야 합니다).

또 다른 방법은 mkfifo. 두 경우 모두, 스스로 청소해야 합니다.

편집하다:

정말 못생긴 해킹이 있지만 누군가가 그것을 개선할 수 있을 것이라고 확신합니다.

#!/bin/bash
exec 3>&1
exec > >( tee >( ( tac && echo _ ) | tac | (read && cat > ./log) ) )

echo "lol"
sleep 5
echo "lol"

echo "finished writing"

exec >&-
exec >&3
exec 3>&-
echo "stdout now reopen"
sleep 1 #wait if the file is still being written asynchronously
cat ./log

작동 방식: 먼저 tee무슨 일이 일어나고 있는지 확인할 수 있는 가 있습니다. 그러면 교체를 위해 다른 프로세스로 출력됩니다. 계속하기 전에 전체 스트림이 완료될 때까지 기다리는 트릭 tac|tac( tac출력을 시작하려면 전체 입력이 필요하므로) 이 있습니다 . 마지막 부분은 실제로 파일로 출력하는 하위 쉘에 있습니다. 물론 최종 셸은 인스턴스화 직후 파일 시스템에 출력 파일을 생성합니다(유일한 줄인 경우). 따라서 입력이 최종적으로 도착할 때까지 기다려 파일 생성을 지연시키는 작업을 먼저 수행해야 합니다. 먼저 echo를 사용하여 더미 라인을 출력한 다음 이를 읽고 삭제하여 이를 달성했습니다. 이러한 read블록은 파일 설명자를 닫아 tac해당 시간이 만료되었음을 나타낼 때까지 차단됩니다. 따라서 stdout 파일 설명자가 최종적으로 닫힙니다. 또한 프로세스 교체를 켜기 전에 원본 파일을 저장하여 stdout마지막에 복원할 수 있었습니다( cat다시 사용하기 위해). 거기에 하나가 있어서 파일이 실제로 너무 일찍 생성되지 않았는지 sleep 5확인할 수 있습니다 . ls마지막 절전 모드는 더 까다롭습니다. 하위 쉘은 비동기식입니다. 출력이 많으면 tac파일이 실제로 존재하기 전에 두 개의 작업이 완료될 때까지 기다리게 됩니다. 따라서 합리적으로 작업이 실제로 완료되었는지 확인하기 위해 다른 작업을 수행하고 싶을 수도 있습니다. 예를 들어, 파일을 최종 사용하기 전 && touch sentinel, 마지막 하위 쉘의 끝에서 .while [ ! -f sentinel ]; do sleep 1; done && rm sentinel

전체적으로 2개의 프로세스 교체가 있으며 내부에는 2개의 서브쉘과 2개의 파이프가 있습니다. 이것은 내가 작성한 것 중 가장 추악한 것 중 하나입니다... 하지만 stdout을 닫을 때만 파일을 생성해야 합니다. 이는 파일 시스템이 준비되면 잘 제어되고 완료될 수 있음을 의미합니다.

답변2

간단한 경우:

output="$(echo "here is a message")"
# [...]
echo "$output"

리디렉션에서 읽어야 하고 다음과 같은 파이프를 사용할 수 없다면 그렇게 간단하지 않습니다.

echo "$output" | while IFS= read -r line; do :; done

FIFO 및 백그라운드 프로세스를 사용할 수 있습니다.

mkfifo fifo
echo "$output" >fifo &
while IFS= read -r line; do :; done <fifo

티셔츠 버전

mkfifo fifo
( output="$(cat fifo)"; echo "$output" >fifo ) &
exec 3>&1
exec >fifo
...
exec 1>&3
cat fifo

관련 정보