일부 Bourne과 유사한 쉘에서는 read
내장 명령이 파일의 전체 행을 읽을 수 없습니다 /proc
(다음 명령은 에서 실행해야 하며 zsh
다른 $=shell
쉘로 대체해야 함 $shell
).
$ for shell in bash dash ksh mksh yash zsh schily-sh heirloom-sh "busybox sh"; do
printf '[%s]\n' "$shell"
$=shell -c 'IFS= read x </proc/sys/fs/file-max; echo "$x"'
done
[bash]
602160
[dash]
6
[ksh]
602160
[mksh]
6
[yash]
6
[zsh]
6
[schily-sh]
602160
[heirloom-sh]
602160
[busybox sh]
6
read
표준에서는 표준 입력이 텍스트 파일이어야 함을 요구합니다., 이 요구 사항으로 인해 다른 동작이 발생합니까?
POSIX 정의 읽기텍스트 파일, 몇 가지 확인을 수행했습니다.
$ od -t a </proc/sys/fs/file-max
0000000 6 0 2 1 6 0 nl
0000007
$ find /proc/sys/fs -type f -name 'file-max'
/proc/sys/fs/file-max
NUL
내용에 문자가 없으며 /proc/sys/fs/file-max
일반 find
파일로도 보고됩니다(이것은 의 버그입니까 find
?).
나는 쉘이 다음과 같이 뒤에서 뭔가를 하고 있다고 생각합니다 file
.
$ file /proc/sys/fs/file-max
/proc/sys/fs/file-max: empty
답변1
문제는 /proc
Linux에서 이러한 파일이 stat()/fstat()
텍스트 파일처럼 보이지만 그렇게 동작하지 않는다는 것입니다.
동적 데이터이기 때문에 read()
해당 데이터에 대해 하나의 시스템 호출만 수행할 수 있습니다(적어도 일부 데이터에 대해서는). 여러 작업을 수행하면 내용이 다른 두 개의 청크가 발생할 수 있으므로 두 번째 작업은 아무것도 반환하지 않는 것 같습니다 read()
(파일 끝을 의미함)( lseek()
처음으로 돌아가지 않는 한(그리고 시작 부분만)).
유틸리티 read
는 한 번에 한 바이트씩 파일의 내용을 읽어 개행 문자만 읽혀지도록 해야 합니다. 이것은 dash
:
$ strace -fe read dash -c 'read a < /proc/sys/fs/file-max'
read(0, "1", 1) = 1
read(0, "", 1) = 0
일부 쉘은 너무 많은 시스템 호출을 bash
실행하지 않도록 최적화하는 것을 좋아합니다. read()
먼저 파일이 검색 가능한지 확인하고, 그렇다면 파일을 덩어리로 읽습니다. 이미 파일을 읽었다면 커서를 개행 문자 뒤에 다시 놓을 수 있다는 것을 알고 있습니다.
$ strace -e lseek,read bash -c 'read a' < /proc/sys/fs/file-max
lseek(0, 0, SEEK_CUR) = 0
read(0, "1628689\n", 128) = 8
를 사용하면 bash
128바이트보다 크고 단일 읽기 시스템 호출에서만 읽을 수 있는 proc 파일에 여전히 문제가 발생합니다.
bash
-d
이 옵션을 사용하면 이 최적화도 비활성화된 것으로 나타납니다.
ksh93
추가 최적화는 심지어 거짓이 됩니다. ksh93은 read
역추적을 수행하지만 next를 위해 읽은 추가 데이터를 기억하므로 read
next (또는 또는 read
와 같은 데이터를 읽는 다른 내장 함수 )는 다른 명령 간에 해당 데이터를 시도하지도 않습니다 (수정된 경우에도). :cat
head
read
$ seq 10 > a; ksh -c 'read a; echo test > a; read b; echo "$a $b"' < a
1 2
$ seq 10 > a; sh -c 'read a; echo test > a; read b; echo "$a $b"' < a
1 st
답변2
알고 싶으시다면왜?이렇습니다. 커널 소스 코드에서 답을 볼 수 있습니다.여기:
if (!data || !table->maxlen || !*lenp || (*ppos && !write)) {
*lenp = 0;
return 0;
}
기본적으로 read() 는 숫자인 sysctl 값에 대한 *ppos
조회(0이 아닌 값)를 구현하지 않습니다 . 읽기가 완료될 때마다 !write
구성 항목에서 /proc/sys/fs/file-max
관련 루틴이 호출됩니다.__do_proc_doulongvec_minmax()
file-max
테이블같은 파일에.
/proc/sys/kernel/poweroff_cmd
via 와 같은 다른 항목은 조회를 허용하므로 아무 문제 없이 해당 항목에 대해 작업하고 셸에서 읽을 proc_dostring()
수 있습니다 .dd bs=1
커널 2.6부터 대부분의 /proc
읽기는 다음과 같은 새로운 API를 통해 구현됩니다.
시퀀스 파일
이는 검색을 지원하므로 예를 들어 읽는 데 /proc/stat
문제가 발생해서는 안 됩니다. 보시다시피 /proc/sys/
구현에서는 이 API를 사용하지 않습니다.
답변3
첫 번째 시도에서는 반환 값이 실제 Bourne Shell 또는 그 파생물(sh, bosh, ksh, heirloom)의 반환 값보다 작은 셸의 버그처럼 보입니다.
원래 Bourne Shell은 블록(64바이트)을 읽으려고 시도하지만 최신 Bourne Shell 변형은 128바이트를 읽습니다. 그러나 줄바꿈이 없으면 다시 읽기 시작합니다.
배경: /procfs 및 유사한 구현(예: 마운트된 /etc/mtab
가상 파일)에는 동적 콘텐츠가 있으며 stat()
호출로 인해오락첫 번째는 동적 콘텐츠입니다. 따라서 해당 파일의 크기(읽기부터 EOF까지)는 stat()
반환된 크기와 다를 수 있습니다.
POSIX 표준은 유틸리티가 기대하는 것을 요구한다는 점을 감안할 때짧은 독서언제든지 소프트웨어는 read()
a의 반환 값이 다음보다 작은 것으로 간주합니다.이미 주문함EOF로 표시된 바이트 수가 손상되었습니다. read()
반환값이 예상보다 작으면 0이 반환될 때까지 올바르게 구현된 유틸리티가 다시 호출됩니다. read
내장 케이스 의 경우는 물론 까지만 읽어도 충분합니다.EOF
또는NL
당신이 볼 때까지 .
트러스 클론을 실행하면 실험에서만 반환된 셸의 잘못된 동작을 truss
확인할 수 있습니다 .6
이 특별한 경우에는 Linux 커널 버그인 것으로 보입니다. 다음을 참조하세요.
$ sdd -debug bs=1 if= /proc/sys/fs/file-max
Simple copy ...
readbuf (3, 12AC000, 1) = 1
writebuf (1, 12AC000, 1)
8readbuf (3, 12AC000, 1) = 0
sdd: Read 1 records + 0 bytes (total of 1 bytes = 0.00k).
sdd: Wrote 1 records + 0 bytes (total of 1 bytes = 0.00k).
리눅스 커널 반환0두 번째 경우에는 read
이는 확실히 사실이 아닙니다.
결론: 처음에 충분히 큰 데이터 블록을 읽으려고 시도하는 셸은 이 Linux 커널 버그를 유발하지 않습니다.
답변4
/proc 아래의 파일은 때때로 NULL 문자를 사용하여 파일 내의 필드를 구분합니다. 읽기가 이 문제를 처리할 수 없는 것 같습니다.