머리는 여분의 캐릭터를 먹는다 그래서 구현은 여전히 추가 문자를 먹는다 12345. 이

다음 쉘 명령은 입력 스트림의 홀수 행만 인쇄해야합니다.

echo -e "aaa\nbbb\nccc\nddd\n" | (while true; do head -n 1; head -n 1 >/dev/null; done)

그러나 대신 첫 번째 줄을 인쇄합니다 aaa.

-c( --bytes) 옵션 과 함께 사용하면 마찬가지입니다 .

echo 12345678901234567890 | (while true; do head -c 5; head -c 5 >/dev/null; done)

이 명령 1234512345은 예상대로 출력 됩니다. 그러나 이것은 유틸리티 의 coreutils 구현 에서만 작동 head합니다. 비지 박스의 출력이 단지 그래서 구현은 여전히 추가 문자를 먹는다 12345.

이 특정 구현 방법은 최적화 목적으로 수행 된 것 같습니다. 줄이 끝나는 곳을 알 수 없으므로 읽을 문자 수를 알 수 없습니다. 입력 스트림에서 추가 문자를 사용하지 않는 유일한 방법은 스트림을 바이트 단위로 읽는 것입니다. 그러나 한 번에 한 바이트 씩 스트림에서 읽는 것이 느려질 수 있습니다. 따라서 head입력 스트림을 충분히 큰 버퍼로 읽은 다음 해당 버퍼의 행을 계산합니다.

--bytes옵션을 사용 하는 경우에도 마찬가지 입니다. 이 경우 읽을 바이트 수를 알고 있습니다. 따라서이 바이트 수만큼 정확하게 읽을 수 있습니다. corelibs의 구현은이 기회를 사용하지만, 비지 박스의 하나하지, 그것은 여전히 버퍼에 필요한 것보다 더 많은 바이트를 읽어 않습니다. 아마도 구현을 단순화하기 위해 수행되었을 것입니다.

그래서 질문입니다. head유틸리티가 요청한 것보다 많은 문자를 입력 스트림에서 소비 하는 것이 맞 습니까? 유닉스 유틸리티에는 어떤 종류의 표준이 있습니까? 그리고 있다면,이 동작을 지정합니까?

추신

Ctrl+C위의 명령을 중지하려면 을 눌러야 합니다. 유닉스 유틸리티는 그 이상을 읽는 데 실패하지 않습니다 EOF. 누르기를 원하지 않으면 더 복잡한 명령을 사용할 수 있습니다.

echo 12345678901234567890 | (while true; do head -c 5; head -c 5 | [ `wc -c` -eq 0 ] && break >/dev/null; done)

나는 단순성을 위해 사용하지 않았다.



답변

헤드 유틸리티가 입력 스트림에서 요청한 것보다 많은 문자를 소비하는 것이 맞습니까?

예, 허용됩니다 (아래 참조).

유닉스 유틸리티에는 어떤 종류의 표준이 있습니까?

예, POSIX 3 권, Shell & Utilities .

그리고 있다면,이 동작을 지정합니까?

소개에서 :

표준 유틸리티가 탐색 가능한 입력 파일을 읽고 파일 끝에 도달하기 전에 오류없이 종료되는 경우, 유틸리티는 열린 파일 설명의 파일 오프셋이 유틸리티가 처리 한 마지막 바이트 바로 위에 위치하는지 확인해야합니다. 찾을 수없는 파일의 경우 해당 파일에 대한 열린 파일 설명의 파일 오프셋 상태는 지정되지 않습니다.

head표준 유틸리티 중 하나 이므로 POSIX 호환 구현은 위에서 설명한 동작을 구현해야합니다.

GNU head 파일 디스크립터를 올바른 위치에 두려고 시도하지만 파이프를 찾는 것은 불가능하므로 테스트에서 위치를 복원하지 못합니다. 당신은 이것을 사용하여 볼 수 있습니다 strace:

$ echo -e "aaa\nbbb\nccc\nddd\n" | strace head -n 1
...
read(0, "aaa\nbbb\nccc\nddd\n\n", 8192) = 17
lseek(0, -13, SEEK_CUR)                 = -1 ESPIPE (Illegal seek)
...

read반환 17 바이트 (사용 가능한 모든 입력), head그 중 네 가지를 처리하고 다시 13 바이트를 이동하려고하지만 할 수 없습니다. (여기서 GNU head가 8 KiB 버퍼를 사용 한다는 것을 알 수 있습니다 .)

당신이 말할 때 head(비표준 인) 바이트를 계산하는 바이트가 읽는 방법, 그것을 알고 그래서 할 수 그에 따라 읽기를 제한 (방법 있음을 구현할 경우). 이것이 head -c 5테스트가 작동하는 이유입니다 . GNU head는 5 바이트 만 읽으므로 파일 디스크립터의 위치를 ​​복원 할 필요가 없습니다.

문서를 파일에 쓰고 대신 사용하면 다음과 같은 동작이 나타납니다.

$ echo -e "aaa\nbbb\nccc\nddd\n" > file
$ < file (while true; do head -n 1; head -n 1 >/dev/null; done)
aaa
ccc


답변

POSIX에서

헤드 유틸리티는 지정된 시점에서 각 파일의 출력을 종료, 표준 출력에 입력 파일을 복사해야한다.

head 입력에서 읽어야 하는 양에 대해서는 아무 것도 말하지 않습니다 . 대부분의 경우 속도가 매우 느리기 때문에 바이트 단위로 읽도록 요구하는 것은 어리석은 일입니다.

그러나 이것은 read내장 / 유틸리티로 해결됩니다. read파이프에서 한 번에 한 바이트 씩 찾을 수있는 모든 쉘 과 표준 텍스트 를 해석하여 한 줄만 읽을 수 있도록 해석해야합니다.

판독 유틸리티는 하나 개 이상의 쉘 변수로 표준 입력 단일 논리 라인을 판독한다.

의 경우 read쉘 스크립트에서 사용되는, 일반적인 사용 사례는 다음과 같이 될 것이다 :

read someline
if something ; then
    someprogram ...
fi

여기서의 표준 입력은 someprogram쉘 의 표준 입력과 동일하지만에 someprogram의해 read버퍼링 된 읽기 후에 남은 것이 아니라에 의해 소비 된 첫 번째 입력 라인 다음에 오는 모든 것을 읽을 수 있습니다 read. 반면에, head예와 같이 사용 하는 것이 훨씬 더 드문 경우입니다.


다른 줄을 모두 삭제하려면 전체 입력을 한 번에 처리 할 수있는 도구를 사용하는 것이 좋습니다 (예 : 더 빠름).

$ seq 1 10 | sed -ne '1~2p'   # GNU sed
$ seq 1 10 | sed -e 'n;d'     # works in GNU sed and the BSD sed on macOS

$ seq 1 10 | awk 'NR % 2'
$ seq 1 10 | perl -ne 'print if $. % 2'


답변

awk '{if (NR%2) == 1) print;}'


답변