필요한 애플리케이션이 있습니다.생산자파일 이름 보내기소비자, 그리고 있습니다생산자지시하다소비자마지막 파일 이름이 전송될 때파일 끝달성.
단순화를 위해 다음 예에서는생산자 시연하려면 및 를 사용 echo
하고 printf
시연하려면 소비자를 사용하세요 cat
. 나는 "여기에 파일을 저장"하는 방법을 추론하려고 했지만 성공하지 못했습니다 <<EOF
.생산자 래퍼(그런 것이 존재한다면) 징후로 찾아야 할 것파일 끝. 유효한 경우 출력에서 필터링 cat
되어야 합니다 .EOF
예 1)
입력하다
{
echo "Hello World!"
printf '\x04'
echo "EOF"
} <<EOF |\
cat
산출
bash: warning: here-document at line 146 delimited by end-of-file (wanted `EOF')
Hello World!
EOF
예시 2)
입력하다
{
echo "Hello World!"
printf '\x04'
echo "EOF"
} |\
cat <<EOF
산출
bash: warning: here-document at line 153 delimited by end-of-file (wanted `EOF')
구분 기호를 표시하기 위한 "여기에 파일을 저장"하는 방법이 정적 텍스트에만 작동하고 동적으로 생성된 텍스트에는 작동하지 않는다는 것이 맞습니까?
--실용적인 응용 프로그램--
inotifywait -m --format '%w%f' /Dir | <consumer>
소비자는 /Dir 디렉터리에 파일이 기록되기를 기다리고 있습니다. "/Dir/EOF" 파일이 작성되면 소비자는 다음과 같이 쉘 스크립트를 작성하여 논리적 파일 끝 조건을 감지할 수 있습니다.
inotifywait -m --format '%w%f' /Dir |<</Dir/EOF <consumer>
——자일스의 답변에 대한 응답——
이론적으로 가능합니까?
cat <<EOF
hello
world
EOF
~처럼
SpecialSymbol="EOF"
{
echo hello
echo world
echo $SpecialSymbol
} |\
while read Line; do
if [[ $Line == $SpecialSymbol ]]
break
else
echo $Line
fi
done |\
cat
이론적으로는 어쩌면 내 말은"기존 사용 패턴을 지원하고 이전에 불법적인 구문이 있는 추가 사용 패턴만 활성화합니까?"- 기존 법률 및 규정이 훼손되지 않음을 의미합니다.
답변1
파이프의 경우 모든 생산자가 파이프의 파일 설명자를 닫고 소비자가 모든 데이터를 읽은 후에 소비자는 파일의 끝을 봅니다.
따라서:
{
echo foo
echo bar
} | cat
cat
echo
두 번째 항목이 종료되고 합계가 cat
읽혀지면 파일의 끝이 표시됩니다. 더 이상 할 일이 없습니다.foo\n
bar\n
그러나 기억해야 할 점은 파이프 왼쪽의 일부 명령이 일부 백그라운드 프로세스를 시작하면 해당 백그라운드 프로세스가 파이프의 fd(stdout)를 상속하므로 cat
해당 프로세스도 종료될 때까지 eof 또는 종료가 표시되지 않는다는 것입니다. 표준 출력. 좋다:
{
echo foo
sleep 10 &
echo bar
} | cat
cat
반환 없이 10초가 경과한 것을 볼 수 있습니다 .
sleep
여기에서 stdout을 다른 것으로 리디렉션 할 수 있습니다 . 예를 들어 /dev/null
해당 (비) 출력이 다음으로 공급되는 것을 원하지 않는 경우 cat
:
{
echo foo
sleep 10 > /dev/null &
echo bar
} | cat
왼쪽 서브셸에서 마지막 명령을 실행하기 전에 파이프의 쓰기 끝을 닫으려면 |
stdout을 닫거나 중간에 있는 서브셸로 리디렉션을 사용할 수 있습니다 exec
. 예를 들면 다음과 같습니다.
{
echo foo
exec > /dev/null
sleep 10
} | (cat; echo "cat is now gone")
그러나 대부분의 쉘은 명령 외에도 이 하위 쉘을 기다립니다 cat
. 따라서 읽은 후 cat is now gone
즉시 볼 수 있지만 foo
전체 파이프라인이 완료될 때까지 10초를 기다려야 합니다. 물론 위의 예에서는 다음과 같이 작성하는 것이 더 합리적입니다.
echo foo | cat
sleep 10
<<ANYTHING...content...ANYTHING
명령의 표준 입력을 다음을 포함하는 파일로 만드는 여기 문서입니다.콘텐츠. 거기에는 소용이 없습니다. \4
는 터미널에서 읽을 때 터미널 장치에 저장된 데이터가 데이터를 읽는 응용 프로그램으로 플러시되는 바이트입니다(데이터가 없으면 read()
0이 반환되어 파일의 끝을 나타냄). 다시 말하지만 여기서는 유용한 것이 없습니다.
답변2
귀하의 시도에 대한 문제는 귀하가 "여기에 파일을 저장하는 방법"이라고 부르는 것이 존재하지 않는다는 것입니다. 여기에 있는 파일은 쉘 프로그래밍 언어의 구문 기능입니다. 예를 들어 로 대체되지 않습니다 cat
.
여기에 문서가 포함된 쉘 스크립트를 고려하십시오.
cat <<EOF
hello
world
EOF
작동 방식은 스크립트를 구문 분석하는 과정에서 쉘 인터프리터가 here 문서 구문 구조를 보는 것입니다. 이러한 코드 줄을 실행할 때 인터프리터는 데이터를 수집하여 cat
셸에 따라 input 으로 전달합니다.
echo 'hello
world
' >/tmp/heredoc.tmp
cat </tmp/heredoc.tmp
rm /tmp/heredoc.tmp
(그러나 임시 파일의 보다 현명한 관리) 또는
echo 'hello
world
' | cat
echo EOF
여기서 문서의 끝을 나타내기를 원하는 경우 명령의 출력 echo
은 셸이어야 합니다 .
{
echo 'cat <<EOF'
echo hello
echo world
echo EOF
} | sh
이것은 작동하지만 거의 유용하지 않습니다.
이 중 어느 것도 당신이 계획한 일을 성취하는 데 도움이 되지 않습니다. 여기에 있는 문서에는 다른 입력보다 끝내기가 "더 어렵게" 만드는 마법 같은 것이 없습니다. 파일 끝은 입력 채널을 통해 전송되는 마커가 아니라 입력 채널의 조건입니다. 입력이 일반 파일인 경우 애플리케이션이 파일의 마지막 바이트를 읽으려고 시도하면 파일 끝 조건이 트리거됩니다. 입력이 파이프(이름이 지정되거나 지정되지 않음)인 경우 애플리케이션이 읽기를 시도하지만 생산자가 파이프를 닫으면 파일 끝 조건이 트리거됩니다.
보통은 그냥 써도 충분해요
producer | consumer
종료 시 producer
파이프의 쓰기 끝은 더 이상 열려 있는 프로세스가 없기 때문에 닫힙니다. 파이프를 일찍 닫으려면 생산자가 표준 출력( exec >&-
sh, close(1)
C)을 닫도록 준비하십시오.
파이프의 파일 끝에 도달하려면 파이프의 쓰기 쪽을 연 모든 프로세스가 파이프를 닫아야 합니다. 생산자가 백그라운드 프로세스를 실행하는 경우 fcntl(1, F_SETFD, fcntl(1, F_GETFC, 0) | FD_CLOEXEC)
파이프( )를 포크하기 전에 실행 시 닫기 플래그를 설정 해야 할 수도 있습니다 .
답변3
FIFO를 사용하고 싶다면 물론 다음과 같이 할 수 있습니다.
스크립트 1
FIFO_PATH="/path/to/fifo"
exec 3<"$FIFO_PATH" # stalls until FIFO is opened for writing, too
while read line; do
: whatever
done <&3
exec 3<&-
: continue script
스크립트 2
FIFO_PATH="/path/to/fifo"
exec 3>"$FIFO_PATH" # stalls until FIFO is opened for reading, too
echo foo >&4
exec 4>&-
: continue script