따라서 이 쉘 스크립트는 다음과 같습니다.
#!/bin/bash
head >/dev/null;
head;
시퀀스 번호(예: seq 10000 | ./sscript)를 사용하여 호출하면 거의 항상 동일한 출력을 제공합니다.
산출:
//blank line
1861
1862
1863
1864
1865
1866
1867
1868
1869
나는 그것을 추적했지만 strace seq 10000 | ./sscript
이 숫자가 정확히 어디서 왔는지 스스로 설명할 수 없었습니다. strace가 끝나면:
write(1, "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14"..., 4096) = 4096
write(1, "1\n1042\n1043\n1044\n1045\n1046\n1047\n"..., 4096) = 4096
write(1, "\n1861\n1862\n1863\n1864\n1865\n1866\n1"..., 4096) = 4096
write(1, "2680\n2681\n2682\n2683\n2684\n2685\n26"..., 4096) = 4096
write(1, "499\n3500\n3501\n3502\n3503\n3504\n350"..., 4096) = 4096
write(1, "18\n4319\n4320\n4321\n4322\n4323\n4324"..., 4096) = 4096
write(1, "7\n5138\n5139\n5140\n5141\n5142\n5143\n"..., 4096) = 4096
write(1, "\n5957\n5958\n5959\n5960\n5961\n5962\n5"..., 4096) = 4096
write(1, "6776\n6777\n6778\n6779\n6780\n6781\n67"..., 4096) = 4096
write(1, "595\n7596\n7597\n7598\n7599\n7600\n760"..., 4096) = 4096
write(1, "14\n8415\n8416\n8417\n8418\n8419\n8420"..., 4096) = 4096
write(1, "3\n9234\n9235\n9236\n9237\n9238\n9239\n"..., 3838) = 3838
write
세 번째 항목만 반환되는 이유는 무엇입니까(경우에 따라 두 번째 항목만 반환됨)?
실제로 스크립트의 두 번째 줄 때문에 반환 줄의 처음 10줄(세 번째 또는 두 번째 쓰기)만 인쇄되지만 head
여전히 손실됩니다.
답변1
head
기본적으로 10줄을 인쇄하지만 이렇게 하면 가능한 한 많은 입력을 읽습니다. GNU에는 head
파일에 총 몇 줄이 있는지 알아야 하는 몇 가지 옵션이 있으므로 다음과 같이 읽는 데 아무런 문제가 없습니다. 가능한 한 많이.
head
8192바이트로 보이는 버퍼를 채우기 위해 가능한 한 많이 읽어옵니다.
~ seq 10000 | strace -fe read ./foo.sh
read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\260e\1\0\0\0\0\0"..., 832) = 832
...
Process 17610 attached
...
[pid 17610] read(0, "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14"..., 8192) = 8192
...
[pid 17611] read(0, "\n1861\n1862\n1863\n1864\n1865\n1866\n1"..., 8192) = 8192
...
처음 두 쓰기는 각각 4096바이트이므로 첫 번째 쓰기에서 사용할 수 있습니다 head
.
타이밍에 따라 다릅니다. 첫 번째 항목이 10줄을 인쇄하고 종료할 때 하나가 성공적으로 제거되면 seq
두 번째 항목이 두 번째 항목에 의해 제거됩니다.write
head
write
head
이것Mike Self의 의견매우 계몽적입니다:
일반 파일을 사용해 보세요.
seq 10000 >/tmp/nums; yourscript </tmp/nums
예상한 대로 동작하는 이유는 head
출력을 사용하여 현재 읽기 지점을 읽기 지점 다음 줄로 재배치하려고 시도하기 때문입니다.lseek()
. 이는 일반 파일, 리디렉션된 파일 등에 대해서는 작동하지만 파이프에는 작동하지 않습니다.
The lseek() function shall fail if:
...
ESPIPE The fildes argument is associated with a pipe, FIFO, or socket.
이는 다음을 사용하여 볼 수 있습니다 strace
.
~ seq 10000 | strace -fe lseek ./foo.sh
...
Process 18561 attached
[pid 18561] lseek(0, -8171, SEEK_CUR) = -1 ESPIPE (Illegal seek)
[pid 18561] +++ exited with 0 +++
--- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=18561, si_uid=1000, si_status=0, si_utime=0, si_stime=0} ---
Process 18562 attached
[pid 18562] lseek(0, -8146, SEEK_CUR) = -1 ESPIPE (Illegal seek)
...