출력이 직렬 콘솔로 리디렉션되는 임베디드 Linux 장치에서 실행되는 데몬이 있습니다.
my_daemon > /dev/ttyS0
그러나 이제 사용자가 exit
직렬 인터페이스에서 셸을 실행하면 직렬 장치가 다시 생성되어 직렬 장치가 일시적으로 사라지고 데몬이 충돌하게 됩니다.
이런 일이 발생하지 않도록 하는 (간단한) 방법이 있나요? 파이프 대상이 사라진 후 다시 연결을 시도하는 래퍼(또는 프로세스와 결합된 명명된 파이프)가 중간에 있을 수 있습니까? "오프라인" 시간을 버퍼링할 필요가 없습니다.
답변1
다음 쉘 함수를 사용하십시오.
relay () (
#!/bin/sh
sink="${1:-/dev/ttyS0}"
exec 4<&0 2>/dev/null
while :; do
cat 3<"$sink" >/proc/self/fd/3
<&4 cat >/dev/null & sleep 2; kill -s PIPE "$!" || exit
done
)
이와 같이:
my_daemon | relay
#!/bin/sh
shebang( )과 같은 것이 함수 내에서는 아무런 의미가 없는 것 같습니다 . 단지 코드가 어떤 쉘을 대상으로 하는지를 나타냅니다. 함수 대신 스크립트를 작성하려면 실행 파일에 함수 본문을 저장하면 shebang이 작동합니다.
몇 가지 팁이 있습니다:
리디렉션이나 유사한 리디렉션을 사용하는
cat >/dev/ttyS0
솔루션 에는 결함이 있을 수 있습니다. "직렬 장치를 다시 생성"한다는 것은/dev/ttyS0
존재하지 않는 시간 창이 있다는 것을 의미한다고 가정합니다 . 또한 코드를 실행하는 사용자(아마도 루트)가 에 액세스할 수 있다고 가정합니다/dev/
.>/dev/ttyS0
해당 파일이 없으면 일반 파일이 생성됩니다. 이렇게 테스트할 수는 있지만! [ -e /dev/ttyS0 ]
테스트 전후에 파일이 사라질 수 있습니다>/dev/ttyS0
.따라서 나는
cat 3<"$sink" >/proc/self/fd/3
기본적$sink
으로 를 사용합니다/dev/ttyS0
. 첫 번째 리디렉션은 읽기 위해 파일을 열려고 시도하고, 두 번째 리디렉션은 stdout을 동일한 파일로 리디렉션하려고 시도합니다. 비결은 두 번째 리디렉션이 새 파일을 생성하지 않는다는 것입니다./dev/ttyS0
또 다른 접근 방식은 사용자가 에 액세스할 수 있지만 에서 파일을 생성할 수 없도록 배열하는 것입니다/dev/
. 이 경우 이 트릭은 필요하지 않으며 사용된 솔루션은>/dev/ttyS0
안전해야 합니다. 어떤 이유로든 액세스할 수 없는 경우 이는 효과적인 방법이 될 수 있습니다/proc/self/fd/3
. 첫 번째cat
는 다음과 같습니다.cat >"$sink"
첫 번째 고양이의 목적은 수신자에게 데이터를 보내는 것입니다. 리디렉션이 실패하거나 수신자가 결국 사라질 수 있습니다. 여기 두 번째 것이 온다
cat
. 두 번째 목적은cat
수신자가 없을 때 데이터를 삭제하는 것입니다. 즉시 다시 생성해야 한다면/dev/ttyS0
두 번째 항목은 필요하지 않습니다cat
. 그러나 귀하의 경우 경로 이름이 빨리 다시 나타날지 확실하지 않습니다. 내 생각에 없으면 대신 계속하고/dev/ttyS0
싶을 것입니다 .my_daemon
예방하다. 두 번째는cat
계속 진행됩니다.단순한
cat >/dev/null
것은 좋은 생각이 아니며/dev/ttyS0
다시 만든 후에도 무기한 실행될 수 있습니다. 비결은 비동기식으로 실행하고 몇 초 후에 종료하는 것입니다. 그러면 코드가 반복되고 첫 번째 코드가cat
싱크를 다시 열려고 시도합니다.<&4
능력이 필요하기 때문에 필요한 것입니다. 작업 제어가 비활성화되면(기본적으로 함수가 있는 서브셸 또는 스크립트에 있음) 명령은&
표준 입력이 리디렉션되거나/dev/null
동등한 파일로 종료됩니다. 이전exec 4<&0
및 this 덕분에<&4
두 번째 것은cat
어쨌든 함수의 표준 입력에서 읽을 수 있습니다.kill
두 번째 항목이cat
더 이상 존재하지 않으면 실패할 가능성이 높습니다sleep 2
. 나가면my_daemon
이런 일이 발생합니다 .kill … || exit
EOF 조건을 감지하는 기술입니다. 예를 들어,date | relay
Due에도 불구하고 종료되어야 합니다sleep
. 이 트릭이 없으면 코드는 무한히 반복됩니다.EOF의 경우 두 번째 PID가
cat
재사용되어kill
잘못된 프로세스를 대상으로 할 수 있습니다. Linux의 AFAIK PID는 순차적으로 할당됩니다. 시퀀스가 약 2초 안에 순환되어 동일한 PID를 얻을 가능성은 거의 없습니다. 트릭은 두 번째 항목이cat
EOF로 인해 일찍 종료 되면kill
확인no such process
하고 실패하므로exit
그런 일이 발생한다고 가정합니다.
기본값은 입니다 $sink
. 첫 번째 명령줄 인수로 지정하여 /dev/ttyS0
다른 경로 이름(예: )을 계속 사용할 수 있습니다 . … | relay foo
일반 파일을 테스트하려면 파일이 열려 있는 동안 삭제해야 합니다.그것을 파괴하지 마십시오. 내 테스트에서는 set -x
무슨 일이 일어나는지 자주 확인하고 Ctrl+d cat
요청 시 쉽게 종료(첫 번째).
내 테스트 플랫폼: Linux 커널 5.15.0, Busybox 1.30.1의 sh
( ).ash
답변2
어쩌면 다음과 같은 것일 수도 있습니다.
버퍼 페이스트 프로그램
#!/bin/sh
while true;do
cat buffer_file > /dev/ttyS0
done
그런 다음 다음을 실행하십시오.
my_daemon > buffer_file
./bufferpaster.sh
답변3
좋습니다. 정보가 없어도 strace
유효한 장치 파일을 확인/기다릴 수 있습니다. 데몬이 줄 바꿈(for read
)으로 끝나는 줄을 출력한다고 가정하면 다음과 같을 수 있습니다.
tty=/dev/ttyS0
my_daemon | (
# Start with a read of 1 line, to catch when the daemon exits, and then "cat" the rest
while read line; do
# check/wait for device file to exist and be writable
until [ -w $tty ]; do sleep 1; done
echo "$line" >> $tty
cat >> $tty
done
)
>>
테스트가 아닌 파일을 먼저 테스트해보고 싶으신 경우를 대비해 첨부합니다 .ttyS0
답변4
stdout을 로그 파일에 쓴 다음 initsystem inittab/systemd tail -F 로그 파일을 직렬 포트에 보냅니다. Init는 tail이 직렬 포트에서 실행되는지 확인하고 사용자는 데몬 작성에 집중할 수 있습니다. 로그 회전을 수행해야 하지만 일부 유틸리티(예: Piper, Multilog)를 사용할 수 있습니다. 다음은 stdout을 파이핑하여 로그 파일을 생성하는 방법에 대한 전체 설명입니다.https://superuser.com/questions/291368/log-rotation-of-stdout)