stdin 및 stdout에서 파일 읽기 및 쓰기

stdin 및 stdout에서 파일 읽기 및 쓰기

bash에서 지속적으로 (더미) 파일을 읽고 써야 합니다.중간에 파일을 닫지 마세요. 나는 읽고 쓰기 위해 파일을 열고, 표준 입력에서 읽고, 읽은 내용을 파일에 쓰고, 파일에서 읽고 표준 출력에 쓰는 프로그램을 찾고 있습니다. 일종의 netcat파일과 비슷합니다.

문제의 파일은 응답을 받기 위해 명령을 쓰고 읽을 수 있는 /sys(내가 작업 중인 작업의 사용자 정의 파일)에 있는 더미 파일입니다. 여기서 쓰기와 후속 읽기는 동일한 세션에 있어야 합니다. 즉, 중간에 닫지 않고 동일한 파일 설명자에 있습니다.

C에서는 쉽습니다. - ,, open("file", O_RDWR)- 참고: 필수는 아닙니다.write()read()seek()

표준 GNU 도구가 있습니까, 아니면 작성해야 합니까?

답변1

잘림 없이 읽기+쓰기 모드로 파일을 여는 리디렉션 연산자는 <>모든 Bourne과 유사한 셸(에 매핑됨 open(file, O_RDWR|O_CREAT)( zshthrow도 발생 하지만 O_NOCTTY) 또는 fopen(file, "w+"))에 있습니다.

exec 3<> "$file"

읽기+쓰기 모드로 파일 설명자 3을 엽니다 $file(존재하지 않는 경우 잘라내지 말고 생성하세요).

그러나 오직 ksh93zsh구하다운영자. dd탐색은 가능하지만 뒤로는 불가능합니다. 변수의 NUL 바이트를 제외하고 어떤 zsh쉘도 이것을 사용할 수 없습니다.

존재하다 zsh:

zmodload zsh/system
exec 3<> $file
sysread -i 3 -c 2 var # a read() of 2 bytes
sysseek -u 3 0 # seek back to beginning
# or sysseek -u 3 -w current -2 # to seek back 2 bytes
syswrite -o 3 something-else
exec 3<&- # close

존재하다 ksh93:

exec 3<> "$file"
var=$(dd bs=2 count=1 <&3 2>/dev/null; echo .)
var=${var%?}
exec 3<#((0)) # seek to beginning
# or exec 3<#((CUR-2)) # to seek back 2 bytes
print -ru3 something-else

이식 가능한 경우 원하는 각 오프셋에 대해 원하는 만큼 파일을 열 수 있습니다. 예를 들어 오프셋 2에서 2바이트를 읽고 쓸 수 있습니다(사용되지 않은 경우 값이 아닌 경우 0바이트) zsh.

var=$(dd bs=2 count=1 skip=1 < "$file"; echo .)
var=${var%?}
printf %s something-else | dd bs=2 seek=1 1<> "$file"

또는:

printf %s something-else | dd bs=2 seek=1 of="$file" conv=notrunc

동일한 파일을 읽고 쓰기 위해 ksh93두 가지 다른 흥미로운 리디렉션 연산자가 있습니다.

tr 01 10 < file >; file

tr출력을 임시 파일에 저장 하고 tr성공하면 이름을 다음으로 바꿉니다 file. 파일이 다시 생성되므로 권한과 소유권이 다를 수 있습니다.

tr -d 0 < file 1<>; file

Standard/Bourne 과 동일 tr -d 0 < file 1<> file하지만 tr성공할 경우 쓰기가 완료된 지점에서 file잘립니다 . tr입력을 읽는 것보다 적은 출력을 생성하는 필터링 명령, 더 정확하게는 이전에 작성된 데이터를 읽지 않는 명령에 대해 이 기능을 사용할 수 있습니다.

zsh프로세스 대체 형태로 다음 =(...)과 같이 사용할 수 있습니다.

 mv =(tr 01 10 < file) file

(효과 및 주의사항과 유사합니다 ksh93.) >;. 또는:

 cp =(tr 01 10 < file) file

이는 속성을 유지 file하지만 추가 복사본을 의미합니다.


이제 동일한 파일 설명자를 사용하여 동일한 오프셋에서 읽고 써야 하고 zsh나 ksh93을 모두 사용할 수 없는 경우 언제든지 perl// python... 로 되돌릴 수 있습니다.ruby

perl -e '
  open F, "<>", "file" or die "open: $!";
  read F, $var, 1;
  seek F, 0, 0;
  print F "something-else"'

이제 질문의 업데이트된 버전을 다시 읽은 후 파일은 일반 검색 가능한 파일보다 소켓 또는 양방향 파이프처럼 보입니다.

이 경우에는 문제가 될 수 있습니다.

socat - file:your-file

또는:

(cat >&3 3>&- & cat <&3 3<&-) 3<> your-file

stdin/stdout에서 데이터를 읽고 이 파일에 데이터를 공급합니다.

각각은 cat셸에서 열린 파일 설명자 3의 자체 복사본을 읽고 쓰지만 동일한 파일 설명자를 공유합니다.파일 설명 열기따라서 동일해야 합니다.

답변2

번역가가 아닌 이상오직, 동시에 안전하게 읽고 쓸 수는 없습니다(변환을 하더라도 프로그램이 오류와 함께 종료되면 파일이 "반번역"될 수 있습니다).

tee및 의 조합을 원하는 것 같습니다 sponge. 당신이 sponge사용할 수있는더 많은 유틸리티표준 입력을 받아 파일에 씁니다. tee를 사용하여 입력을 여러 출력에 복사 할 수 있습니다 .

최종 결과는 다음과 같습니다.

command < filename | tee >(sponge filename)

>()예이다프로세스 교체. 이 예에서 는 stdin으로 이동 하여 기록되는 >(sponge filename)FIFO의 경로로 대체됩니다 . 또한 입력을 표준 출력에 독립적으로 기록합니다.spongeteetee

여기에 예가 있습니다. 출력이 stdout과 파일 모두에 기록되는 것을 볼 수 있습니다.

$ echo 'foo bar' > file
$ sed 's/foo/qux/' < file | tee >(sponge file)
qux bar
$ cat file
qux bar

관련 정보