dd
반복해서 쓸 수 있음\0
바이트파일을 매우 빠르게 쓰지만 반복되는 임의 문자열을 쓸 수는 없습니다.
당신은 가지고 있습니까?배쉬 쉘반복해서 쓰는 방법끈"dd"(포함)만큼 빠릅니까 \0
?
Linux를 사용하면서 6개월 동안 제가 접한 모든 제안은 비슷 하지만 아래에 표시된 것과 printf "%${1}s" | sed -e "s/ /${2}/g"
비교하면 고통스러울 정도로 느리고 약 384MB(내 상자에서) 후에 충돌이 발생합니다. 실제로 이것은 한 줄에 나쁘지 않습니다. 길이 :) - 하지만 무너지네요! 문자열에 개행 문자가 포함되어 있으면 문제가 되지 않을 것 같습니다.dd
sed
sed
dd
printf
+ 와의 속도 비교 sed
:
real user sys
WRITE 384 MB: 'dd' 0m03.833s 0m00.004s 0m00.548s
WRITE 384 MB: 'printf+sed' 1m39.551s 1m34.754s 0m02.968s
# the two commands used
dd if=/dev/zero bs=1024 count=$((1024*384))
printf "%$((1024*1024*384))s" |sed -e "s/ /x/g"
이 작업을 수행하는 방법에 대한 아이디어가 있습니다.배쉬 쉘스크립트를 작성하지만 바퀴를 다시 만들 필요는 없습니다. :)
답변1
$ time perl -e \
'$count=1024*1024; while ($count>0) { print "x" x 384; $count--; }' > out
real 0m1.284s
user 0m0.316s
sys 0m0.961s
$ ls -lh out
-rw-r--r-- 1 me group 384M Apr 16 19:47 out
"x" x 384
(384를 생성하는 문자열) x
을 원하는 것으로 바꾸십시오.
각 루프에서 더 큰 문자열을 사용하고 일반 stdout 버퍼링을 우회하여 이를 더욱 최적화할 수 있습니다.
$ perl -e \
'$count=384; while ($count>0) {
syswrite(STDOUT, "x" x (1024*1024), 1024*1024);
$count--;
}' > out
이 경우 syswrite
호출은 기본 write
시스템 호출에 1M을 전달하므로 매우 좋습니다. (이것으로 사용자당 약 0.940초를 얻었습니다.)
sync
팁: 이전 실행의 플러시가 현재 실행의 I/O를 방해하지 않도록 각 테스트 사이에 이 호출을 호출 해야 합니다 .
참고로 이번에는 다음을 얻습니다.
$ time dd if=/dev/zero bs=1024 count=$((1024*384)) of=./out
393216+0 records in
393216+0 records out
402653184 bytes (403 MB) copied, 1.41404 s, 285 MB/s
real 0m1.480s
user 0m0.054s
sys 0m1.410s
답변2
일반적으로 쉘은 큰 데이터 블록을 처리하는 데 속도가 느린 것으로 알려져 있습니다. 대부분의 스크립트에서는 어떤 데이터 비트가 작을 가능성이 있고 어떤 비트가 클 가능성이 있는지 미리 알 수 있습니다.
- 외부 프로세스를 포크하고 실행하면 지속적인 오버헤드가 발생하므로 작은 데이터를 처리하려면 내장된 셸을 사용하는 것이 좋습니다.
- 전문화된 컴파일 도구가 해석된 범용 언어보다 더 효율적이므로 빅 데이터 처리를 위해 외부 전문 도구에 의존하는 것을 선호합니다.
dd
read
문제 및 통화 에 블록 크기를 사용하십시오 . write
strace(또는 OS에 따라 truss, Trace...)를 사용하여 이를 관찰할 수 있습니다.
$ strace -s9 dd if=/dev/zero of=/dev/null ibs=1024k obs=2048k count=4
✄
read(0, "\0\0\0\0\0\0\0\0\0"..., 1048576) = 1048576
read(0, "\0\0\0\0\0\0\0\0\0"..., 1048576) = 1048576
write(1, "\0\0\0\0\0\0\0\0\0"..., 2097152) = 2097152
read(0, "\0\0\0\0\0\0\0\0\0"..., 1048576) = 1048576
read(0, "\0\0\0\0\0\0\0\0\0"..., 1048576) = 1048576
write(1, "\0\0\0\0\0\0\0\0\0"..., 2097152) = 2097152
✄
대부분의 다른 도구는 최대 버퍼 크기에 대한 상한이 훨씬 낮으므로 더 많은 시스템 호출을 수행하므로 더 많은 시간이 걸립니다. 그러나 이는 비현실적인 벤치마크라는 점에 유의하십시오. 일반 파일, 파이프 또는 소켓에 쓰는 경우 커널은 시스템 호출당 몇 킬로바이트 이상의 데이터를 쓰지 못할 수 있습니다.
답변3
이것을 사용하시면 됩니다 dd
! 먼저 문자열이 파일의 시작 부분에 기록됩니다. 그런 다음 다음을 수행하십시오.
dd if=$FILE of=$FILE bs=$STRING_LENGTH seek=1 count=$REPEAT_TIMES
참고: $STRING_LENGTH가 작은 경우에는 다음을 수행할 수 있습니다.
dd if=$FILE of=$FILE bs=$STRING_LENGTH seek=1 count=$((1024/$REPEAT_TIMES))
dd if=$FILE of=$FILE bs=1024 seek=1 count=$(($REPEAT_TIMES/1024))
(이 예는 STRING_LENGTH가 2의 거듭제곱이고 REPEAT_TIMES가 1024의 배수인 경우에만 작동하지만 이해가 되실 것입니다.)
파일을 덮어쓰는 데 사용하려면(예: 지우기) 다음을 사용하세요.conv=notrunc
답변4
마침내 이 작업을 수행하는 방법에 대한 아이디어를 얻었습니다...이것은 || 근처에서 실행되는 tee
체인을 사용합니다 .tee
tee
dd
# ============================================================================
# repstr
#
# Brief:
# Make multiple (repeat) copies of a string.
# Option -e, --eval is used as in 'echo -e'
#
# Return:
# The resulting string is sent to stdout
#
# Args: Option $1 $2
# -e, --eval COUNT STRING
# repstr $((2**40)) "x" # 1 TB: xxxxxxxxx...
# eg. repstr -e 7 "AB\tC\n" # 7 lines: AB<TAB>C
# repstr 2 "ऑढळ|a" # 2 copies: ऑढळ|aऑढळ|a
#
[[ "$1" == "-e" || "$1" == "--eval" ]] && { e="-e"; shift 1; }|| e=""
count="$1"
string="$2"
[[ "${count}" == "" ]] && exit 1 # $count must be an integer
[[ "${count//[0-9]/}" != "" ]] && exit 2 # $count is not an integer
[[ "${count}" == "0" ]] && exit 0 # nothing to do
[[ "${string}" == "" ]] && exit 0 # nothing to do
#
# ========================================================================
# Find the highest 'power of 2' which, when calculated**, is <= count
# ie. check ascending 'powers of 2'
((leqXpo=0)) # Exponent which makes 2** <= count
((leqCnt=1)) # A count which is <= count
while ((count>=leqCnt)) ;do
((leqXpo+=1))
((leqCnt*=2))
done
((leqXpo-=1))
((leqCnt/=2))
#
# ======================================================================================
# Output $string to 'tee's which are daisy-chained in groups of descending 'powers of 2'
todo=$count
for ((xpo=leqXpo ;xpo>0 ;xpo--)) ;do
tchain=""
floor=$((2**xpo))
if ((todo>=(2**xpo))) ; then
for ((t=0 ;t<xpo ;t++)) ;do tchain="$tchain|tee -" ;done
eval echo -n $e \"'$string'\" $tchain # >/dev/null
((todo-=floor))
fi
done
if ((todo==1)) ;then
eval echo -n $e \"'$string'\" # >/dev/null
fi
#
시간 테스트 결과는 다음과 같습니다.. 제가 만들고 싶었던 테스트 파일의 크기와 비슷해서 32GB까지 늘렸습니다(그래서 이 문제를 해결하기 시작했습니다).
NOTE: (2**30), etc. refers to the number of strings (to achieve a particular GB filesize)
-----
dd method (just for reference) real/user/sys
* 8GB =================================
if=/dev/zero bs=1024 count=$(((1024**2)*8)) # 2m46.941s / 00m3.828s / 0m56.864s
tee method: fewer tests, because it didn't overflow, and the number-of-strings:time ratio is linear
tee method: count string real/user/sys
* 8GB ========== ============ =================================
tee(2**33)>stdout $((2**33)) "x" # 1m50.605s / 0m01.496s / 0m27.774s
tee(2**30)>stdout -e $((2**30)) "xxx\txxx\n" # 1m49.055s / 0m01.560s / 0m27.750s
* 32GB
tee(2**35)>stdout -e $((2**35)) "x" #
tee(2**32)>stdout -e $((2**32)) "xxx\txxx\n" # 7m34.867s / 0m06.020s / 1m52.459s
python method: '.write' uses 'file.write()'
'>stcout' uses 'sys.stdout.write()'. It handles \n in args (but I know very little python)
count string real/user/sys
* 8GB ===== =================== =================================
python(2**33)a .write 2**33 "x" # OverflowError: repeated string is too long
python(2**33)a >stdout 2**33 "x" # OverflowError: repeated string is too long
python(2**30)b .write 2**30 '"xxxxxxxX" *2**0' # 6m52.576s / 6m32.325s / 0m19.701s
python(2**30)b >stdout 2**30 '"xxxxxxxX" *2**0' # 8m11.374s / 7m49.101s / 0m19.573s
python(2**30)c .write 2**20 '"xxxxxxxX" *2**10' # 2m14.693s / 0m03.464s / 0m22.585s
python(2**30)c >stdout 2**20 '"xxxxxxxX" *2**10' # 2m32.114s / 0m03.828s / 0m22.497s
python(2**30)d .write 2**10 '"xxxxxxxX" *2**20' # 2m16.495s / 0m00.024s / 0m12.029s
python(2**30)d >stdout 2**10 '"xxxxxxxX" *2**20' # 2m24.848s / 0m00.060s / 0m11.925s
python(2**30)e .write 2**0 '"xxxxxxxX" *2**30' # OverflowError: repeated string is too long
python(2**30)e >stdout 2**0 '"xxxxxxxX" *2**30' # OverflowError: repeated string is too long
* 32GB
python(2**32)f.write 2**12 '"xxxxxxxX" *2**20' # 7m58.608s / 0m00.160s / 0m48.703s
python(2**32)f>stdout 2**12 '"xxxxxxxX" *2**20' # 7m14.858s / 0m00.136s / 0m49.087s
perl method:
count string real / user / sys
* 8GB ===== =================== =================================
perl(2**33)a .syswrite> 2**33 "a" x 2**0 # Sloooooow! It would take 24 hours. I extrapolated after 1 hour.
perl(2**33)a >stdout 2**33 "a" x 2**0 # 31m46.405s / 31m13.925s / 0m22.745s
perl(2**30)b .syswrite> 2**30 "aaaaaaaA" x 2**0 # 100m41.394s / 11m11.846s / 89m27.175s
perl(2**30)b >stdout 2**30 "aaaaaaaA" x 2**0 # 4m15.553s / 3m54.615s / 0m19.949s
perl(2**30)c .syswrite> 2**20 "aaaaaaaA" x 2**10 # 1m47.996s / 0m10.941s / 0m15.017s
perl(2**30)c >stdout 2**20 "aaaaaaaA" x 2**10 # 1m47.608s / 0m12.237s / 0m23.761s
perl(2**30)d .syswrite> 2**10 "aaaaaaaA" x 2**20 # 1m52.062s / 0m10.373s / 0m13.253s
perl(2**30)d >stdout 2**10 "aaaaaaaA" x 2**20 # 1m48.499s / 0m13.361s / 0m22.197s
perl(2**30)e .syswrite> 2**0 "aaaaaaaA" x 2**30 # Out of memory during string extend at -e line 1.
perl(2**30)e >stdout 2**0 "aaaaaaaA" x 2**30 # Out of memory during string extend at -e line 1.
* 32GB
perl(2**32)f .syswrite> 2**12 "aaaaaaaA" x 2**20 # 7m34.241s / 0m41.447s / 0m51.727s
perl(2**32)f >stdout 2**12 "aaaaaaaA" x 2**20 # 10m58.444s / 0m53.771s / 1m28.498s