코멘트로메이크파일의 "| true"가 "|| true"와 동일한 효과를 갖는 이유가 무엇인지 혼란스럽습니다.사용자웨스트젬썼다:
피해야 할 또 다른 이유
| true
는 명령이 파이프 버퍼를 채울 만큼 충분한 출력을 생성하는 경우 true를 읽기 위해 대기하는 것을 차단한다는 것입니다.
파이프 버퍼의 크기를 알 수 있는 방법이 있나요?
답변1
파이프 버퍼의 용량은 시스템마다 다릅니다(동일한 시스템에서도 다를 수 있음). 파이프의 용량을 찾는 빠르고 쉬운 크로스 플랫폼 방법이 있는지 잘 모르겠습니다.
예를 들어, Mac OS . 파이프 버퍼에서 사용됩니다(참조:xnu/bsd/sys/pipe.h
, 그리고xnu/bsd/kern/sys_pipe.c
; FreeBSD에서 왔기 때문에 동일한 동작이 발생할 수 있습니다.
리눅스파이프(7)매뉴얼 페이지Linux 2.6.11에서는 파이프 용량을 65536바이트로 표시하고 그 이전에는 단일 시스템 페이지(예: (32비트) x86 시스템에서 4096바이트)로 표시합니다. 코드(include/linux/pipe_fs_i.h
, 그리고fs/pipe.c
)는 16개의 시스템 페이지(즉, 시스템 페이지가 4KiB인 경우 64KiB)를 사용하는 것으로 보이지만 파이프당 버퍼는 통과할 수 있습니다.포캉트르파이프에(최대 용량은 기본적으로 1048576바이트이지만 변경될 수 있음 /proc/sys/fs/pipe-max-size
))
여기 조금세게 때리다/진주내 시스템의 파이프 용량을 테스트하는 데 사용한 조합은 다음과 같습니다.
#!/bin/bash
test $# -ge 1 || { echo "usage: $0 write-size [wait-time]"; exit 1; }
test $# -ge 2 || set -- "$@" 1
bytes_written=$(
{
exec 3>&1
{
perl -e '
$size = $ARGV[0];
$block = q(a) x $size;
$num_written = 0;
sub report { print STDERR $num_written * $size, qq(\n); }
report; while (defined syswrite STDOUT, $block) {
$num_written++; report;
}
' "$1" 2>&3
} | (sleep "$2"; exec 0<&-);
} | tail -1
)
printf "write size: %10d; bytes successfully before error: %d\n" \
"$1" "$bytes_written"
다음은 쓰기 크기가 다양한 Mac OS X 10.6.7 시스템에서 실행할 때 찾은 결과입니다(16KiB보다 큰 쓰기에 대한 변경 사항 참고).
% /bin/bash -c 'for p in {0..18}; do /tmp/ts.sh $((2 ** $p)) 0.5; done'
write size: 1; bytes successfully before error: 16384
write size: 2; bytes successfully before error: 16384
write size: 4; bytes successfully before error: 16384
write size: 8; bytes successfully before error: 16384
write size: 16; bytes successfully before error: 16384
write size: 32; bytes successfully before error: 16384
write size: 64; bytes successfully before error: 16384
write size: 128; bytes successfully before error: 16384
write size: 256; bytes successfully before error: 16384
write size: 512; bytes successfully before error: 16384
write size: 1024; bytes successfully before error: 16384
write size: 2048; bytes successfully before error: 16384
write size: 4096; bytes successfully before error: 16384
write size: 8192; bytes successfully before error: 16384
write size: 16384; bytes successfully before error: 16384
write size: 32768; bytes successfully before error: 65536
write size: 65536; bytes successfully before error: 65536
write size: 131072; bytes successfully before error: 0
write size: 262144; bytes successfully before error: 0
Linux 3.19의 동일한 스크립트:
/bin/bash -c 'for p in {0..18}; do /tmp/ts.sh $((2 ** $p)) 0.5; done'
write size: 1; bytes successfully before error: 65536
write size: 2; bytes successfully before error: 65536
write size: 4; bytes successfully before error: 65536
write size: 8; bytes successfully before error: 65536
write size: 16; bytes successfully before error: 65536
write size: 32; bytes successfully before error: 65536
write size: 64; bytes successfully before error: 65536
write size: 128; bytes successfully before error: 65536
write size: 256; bytes successfully before error: 65536
write size: 512; bytes successfully before error: 65536
write size: 1024; bytes successfully before error: 65536
write size: 2048; bytes successfully before error: 65536
write size: 4096; bytes successfully before error: 65536
write size: 8192; bytes successfully before error: 65536
write size: 16384; bytes successfully before error: 65536
write size: 32768; bytes successfully before error: 65536
write size: 65536; bytes successfully before error: 65536
write size: 131072; bytes successfully before error: 0
write size: 262144; bytes successfully before error: 0
참고: PIPE_BUF
C 헤더 파일에 정의된 값(및경로 구성value _PC_PIPE_BUF
), 파이프의 용량을 지정하는 것이 아니라 원자적으로 쓸 수 있는 최대 바이트 수를 지정합니다(참조:POSIX쓰기(2)).
에서 인용include/linux/pipe_fs_i.h
:
/* Differs from PIPE_BUF in that PIPE_SIZE is the length of the actual
memory allocation, whereas PIPE_BUF makes atomicity guarantees. */
답변2
이 쉘 라인은 파이프 버퍼 크기도 표시할 수 있습니다.
M=0; while true; do dd if=/dev/zero bs=1k count=1 2>/dev/null; \
M=$(($M+1)); echo -en "\r$M KB" 1>&2; done | sleep 999
(버퍼가 가득 찰 때까지 차단 파이프에 1k 청크 전송)... 일부 테스트 출력:
64K (intel-debian), 32K (aix-ppc), 64K (jslinux bellard.org) ...Ctrl+C.
printf를 사용하는 가장 짧은 bash-one-liner:
M=0; while printf A; do >&2 printf "\r$((++M)) B"; done | sleep 999
답변3
다음은 쉘 명령만 사용하여 실제 파이프 버퍼 용량을 탐색하는 몇 가지 추가 대안입니다.
# get pipe buffer size using Bash
yes produce_this_string_as_output | tee >(sleep 1) | wc -c
# portable version
( (sleep 1; exec yes produce_this_string_as_output) & echo $! ) |
(pid=$(head -1); sleep 2; kill "$pid"; wc -c </dev/stdin)
# get buffer size of named pipe
sh -c '
rm -f fifo
mkfifo fifo
yes produce_this_string_as_output | tee fifo | wc -c &
exec 3<&- 3<fifo
sleep 1
exec 3<&-
rm -f fifo
'
# Mac OS X
#getconf PIPE_BUF /
#open -e /usr/include/limits.h /usr/include/sys/pipe.h
# PIPE_SIZE
# BIG_PIPE_SIZE
# SMALL_PIPE_SIZE
# PIPE_MINDIRECT
답변4
Python >= 3.3의 값이 필요한 경우 간단한 방법은 다음과 같습니다(call out을 실행할 수 있다고 가정 dd
).
from subprocess import Popen, PIPE, TimeoutExpired
p = Popen(["dd", "if=/dev/zero", "bs=1"], stdin=PIPE, stdout=PIPE)
try:
p.wait(timeout=1)
except TimeoutExpired:
p.kill()
print(len(p.stdout.read()))