답변1
순환 I/O 루프 구현tail -f
이는 순환 I/O 루프를 구현합니다.
$ echo 1 >file
$ tail -f file | while read n; do echo $((n+1)); sleep 1; done | tee -a file
2
3
4
5
6
7
[..snip...]
이것은 언급한 사인 알고리즘을 사용하여 루프 입력/출력 루프를 구현합니다.
$ echo 1 >file
$ tail -f file | while read n; do echo "1+s(3*$n)" | bc -l; sleep 1; done | tee -a file
1.14112000805986722210
.72194624281527439351
1.82812473159858353270
.28347272185896349481
1.75155632167982146959
[..snip...]
여기서는 bc의 사인함수 표현인 bc
부동소수점 연산을 수행한다 .s(...)
변수를 사용하여 동일한 알고리즘 구현
이 특정 수학 예제에서는 순환 I/O 방법이 필요하지 않습니다. 간단하게 변수를 업데이트할 수 있습니다.
$ n=1; while true; do n=$(echo "1+s(3*$n)" | bc -l); echo $n; sleep 1; done
1.14112000805986722210
.72194624281527439351
1.82812473159858353270
.28347272185896349481
[..snip...]
답변2
이를 위해 에서 생성한 FIFO를 사용할 수 있습니다 mkfifo
. 하지만 그점은 참고해주세요매우실수로 교착 상태가 발생하기 쉽습니다. 설명하겠습니다. 가상의 "루프"를 예로 들어 보겠습니다. 명령의 출력을 입력에 공급합니다. 교착 상태가 발생할 수 있는 방법은 최소한 두 가지가 있습니다.
이 명령에는 출력 버퍼가 있습니다. 부분적으로 채워졌으나 플러시되지 않았습니다(실제로 작성됨). 가득 차면 이 작업이 수행됩니다. 따라서 읽기 입력이 반환됩니다. 기다리고 있는 입력이 실제로 출력 버퍼에 있기 때문에 영원히 거기에 있을 것입니다. 입력을 받을 때까지 플러시되지 않습니다.
이 명령에는 작성할 출력이 많이 있습니다. 쓰기가 시작되지만 커널 파이프 버퍼가 가득 찼습니다. 따라서 버퍼에서 공간을 사용할 수 있을 때까지 대기합니다. 입력을 읽은 후에는 출력에 무엇이든 쓰기가 끝날 때까지 그런 일을 하지 않기 때문에 결코 일어나지 않는다는 것입니다.
즉, 수행 방법은 다음과 같습니다. 이 예에서는 를 사용하여 od
끝이 없는 16진수 덤프 체인을 만듭니다.
mkfifo fifo
( echo "we need enough to make it actually write a line out"; cat fifo ) \
| stdbuf -i0 -o0 -- od -t x1 | tee fifo
결국에는 중지됩니다. 왜? 교착 상태입니다. 위의 #2입니다. stdbuf
버퍼링을 비활성화하라는 호출이 표시될 수도 있습니다 . 그것을 갖고 있지 않습니까? 교착 상태, 출력 없음.
답변3
아시다시피, 다이어그램에서 설명하는 것처럼 반복적인 피드백 루프가 반드시 필요하다고는 생각하지 않습니다.지속성 있는사이의 파이프공동 프로세스. 그러면 다시 말하지만 그다지 큰 차이는 없을 것입니다. 일단 coprocess에서 행을 열면 일반적인 스타일 루프를 구현하고 아무 작업도 수행하지 않고도 여기에 정보를 쓰고 정보를 읽을 수 있습니다. 매우 특이한 점 .
첫째, bc
코루틴의 주요 후보인 것 같습니다. 의사코드에서 요구하는 것과 거의 유사한 기능을 수행하는 함수를 bc
사용할 수 있습니다 . define
예를 들어, 이를 수행하는 매우 간단한 함수는 다음과 같습니다.
printf '%s()\n' b c a |
3<&0 <&- bc -l <<\IN <&3
a=1; b=0; c=0;
define a(){ "a="; return (a = c+1); }
define b(){ "b="; return (b = 3*a); }
define c(){ "c="; return (c = s(b)); }
IN
...이것이 인쇄됩니다...
b=3
c=.14112000805986722210
a=1.14112000805986722210
하지만 당연히 그렇지 않지마지막. 파이프를 담당하는 printf
서브쉘이 종료되면printf
( a()\n
파이프에 쓴 직후)파이프가 제거되고 bc
입력이 닫히고 종료됩니다. 이것은 상상했던 것보다 훨씬 덜 유용합니다.
@derobert가 이미 언급했습니다.선입선출이 작업은 다음을 생성하여 수행할 수 있습니다.명명된 파이프이 mkfifo
유틸리티를 사용하여 파일을 생성합니다. 시스템 커널이 파일 시스템 항목을 양쪽 끝에 연결한다는 점을 제외하면 이것들은 본질적으로 파이프일 뿐입니다. 이는 매우 유용하지만 파일 시스템에서 스누핑 위험 없이 파이프만 사용할 수 있다면 더 좋을 것입니다.
공교롭게도 쉘에서는 이 작업을 자주 수행합니다. 사용중인 쉘이 구현하는 경우프로세스 교체그러면 아주 간단한 방법으로 얻을 수 있습니다일종의 튼튼한 나사파이프 - 통신할 수 있는 백그라운드 프로세스에 할당할 수 있는 유형입니다.
예를 들어 bash
프로세스 대체가 어떻게 작동하는지 확인할 수 있습니다.
bash -cx ': <(:)'
+ : /dev/fd/63
보시다시피 이것은 실제로치환. 쉘은 확장 중에 경로에 해당하는 값을 대체합니다.협회에관로. 이를 활용할 수 있습니다. ()
교체 자체에서 실행 중인 프로세스와 통신하기 위해 해당 파이프를 사용하는 것으로 제한할 필요는 없습니다.
bash -c '
eval "exec 3<>"<(:) "4<>"<(:)
cat <&4 >&3 &
echo hey cat >&4
read hiback <&3
echo "$hiback" here'
...인쇄...
hey cat here
이제 나는 다른 껍질이 할 수 있다는 것을 안다공동 프로세스bash
다양한 방법으로 수행하세요. 설정을 위한 특정 구문이 있습니다.(어쩌면 하나 zsh
)- 그런데 이게 어떻게 작동하는지 모르겠어요. 내가 아는 것은 bash
and에서 모든 지루한 작업을 수행 할 필요 없이 위의 구문을 사용하여 거의 동일한 작업을 수행할 수 있다는 것입니다 . 그리고 zsh
여기 문서를 통해 매우 유사한 작업을 수행하고 동일한 작업을 달성 할 수 있다는 것입니다.dash
busybox ash
(여기서 문서는 다른 두 파일처럼 임시 파일 대신 파이프를 사용하기 때문 dash
입니다 busybox
).
그래서 적용해보면 bc
...
eval "exec 3<>"<(:) "4<>"<(:)
bc -l <<\INIT <&4 >&3 &
a=1; b=0; c=0;
define a(){ "a="; return (a = c+1); }
define b(){ "b="; return (b = 3*a); }
define c(){ "c="; return (c = s(b)); }
INIT
export BCOUT=3 BCIN=4 BCPID="$!"
...그게 가장 어려운 부분이에요. 여기 재미있는 부분이 있습니다 ...
set --
until [ "$#" -eq 10 ]
do printf '%s()\n' b c a >&"$BCIN"
set "$@" "$(head -n 3 <&"$BCOUT")"
done; printf %s\\n "$@"
...인쇄...
b=3
c=.14112000805986722210
a=1.14112000805986722210
#...24 more lines...
b=3.92307618030433853649
c=-.70433330413228041035
a=.29566669586771958965
...아직 실행 중이에요...
echo a >&"$BCIN"
read a <&"$BCOUT"
echo "$a"
bc
... 함수를 a
호출하여 s를 증가시키고 인쇄하는 대신 s의 마지막 값을 가져올 수 있습니다 ...a()
.29566669586771958965
사실, 내가 그것을 죽이고 IPC 파이프를 찢을 때까지 계속 실행됩니다...
kill "$BCPID"; exec 3>&- 4>&-
unset BCPID BCIN BCOUT
답변4
일반적으로 저는 Makefile(make 명령)을 사용하여 다이어그램을 makefile 규칙에 매핑하려고 합니다.
f1 f2 : f0
command < f0 > f1 2>f2
반복/루프 명령을 사용하려면 반복 전략을 정의해야 합니다. 그리고:
SHELL=/bin/bash
a.out : accumulator
cat accumulator <(date) > a.out
cp a.out accumulator
accumulator:
touch accumulator #initial value
각각은 make
동시에 반복을 생성합니다.