일부 실험을 위해 대용량 파일을 생성하고 싶습니다.
이것은 내 스크립트입니다. 파일을 생성한 다음 변수로 읽은 다음 루프에서 정의된 횟수만큼 파일에 쓰려고 시도합니다.
#! /usr/bin/env bash
set -e
set -u
< /dev/urandom tr -dc "\t\n [:alnum:]" | head -c32768 > temp.txt
data=$(cat ./temp.txt)
for testdir in "$@"; do
echo "create directory '$testdir'"
mkdir -p $testdir
for i in {1..3}; do
counter=$(printf %02d $i)
testfile=$testdir/test_${testdir##*/}_$counter.txt
echo "create file '$testfile'"
echo "$data" > $testfile
done
done
이 스크립트를 사용하여 3000개의 파일(각 폴더에는 3개의 파일이 있음)을 생성하려고 하면 시스템에서 약 19초가 걸립니다.
시간 generateUserData.sh 테스트 {0..1000}
create directory 'TEST999'
create file 'TEST999/test_TEST999_01.txt'
create file 'TEST999/test_TEST999_02.txt'
create file 'TEST999/test_TEST999_03.txt'
create directory 'TEST1000'
create file 'TEST1000/test_TEST1000_01.txt'
create file 'TEST1000/test_TEST1000_02.txt'
create file 'TEST1000/test_TEST1000_03.txt'
real 0m19.333s
user 0m14.791s
sys 0m4.784s
echo
나는 이것이 느린 부분일지도 모른다는 것을 안다 . 가능한 한 빨리 그를 끝내는 방법에 대한 아이디어가 있습니까?
답변1
느린 프로세스는 프로세스를 분기하고 외부 명령을 실행하는 것이 좋습니다.mkdir
counter=$(printf %02d $i)
또한 bash에서 프로세스를 포크합니다. 다음과 같이 작성하면 이를 방지할 수 있습니다.
printf -v counter %02d "$i"
또는:
printf -v testfile %s/%s_%02d.txt "$testdir" "${testdir##*/}" "$i"
mkdir
파일당 하나씩 실행하는 대신 한 번의 호출로 모든 디렉터리를 만듭니다( mkdir -p -- "$@"
; 잊지 마세요) .--
mkdir
다음 중 하나에 임시 파일이 필요하지 않습니다.
data=$(< /dev/urandom tr -dc "\t\n [:alnum:]" | head -c32768; echo .)
data=${data%.}
.
명령 대체가 제거되므로 32768바이트를 포함하도록 보장 하려면 $data
추가가 필요합니다.모두후행 개행 문자. 또한 아무도 추가되지 echo
않는다는 점에 유의하세요 . -n
임의의 데이터의 경우 printf
어쨌든 대신 사용해야 합니다.echo
또한 head -c 32768
문자가 아닌 32768바이트를 제공하므로 문자가 중간에 잘릴 수 있습니다.
printf %s "$data" > "$file"
답변2
뭔가를 참다스티븐 차제라스그들은 약간의 수정을 가한 훌륭한 답변으로 말했습니다.
#!/usr/bin/env bash
set -e
set -u
main() {
< /dev/urandom tr -dc "\t\n [:alnum:]" | dd iflag=fullblock of=./temp.txt bs=32K count=1
mkdir -p -- "${@:?}"
for testdir in "$@"; do
for i in {1..3}; do
printf "%s/%s_%02d.txt\n" "$testdir" "${testdir##*/}" "$i"
done
done | xargs -n1 -P${proc:-16} cp ./temp.txt
}
time main "${@}"
dd
- 정확한 바이트 수를 얻는 다른 방법(비록 한 번만 발생하므로 어느 쪽이든 큰 차이는 없음)- 이 모든 것이
echo
1000을 세게 되었을 때 약 3초가 추가되었습니다. - 멀티스레드, 런타임 시 조정 가능(
proc
변수를 통해) - 시스템에 가장 적합한 값을 찾으세요.
예를 들어
proc=32 bash ./foo.sh {1..1000}
참고 - 변수 채우기에 대한 원래 질문이 인스턴스라고 가정합니다.XY 문제... 만약에예이것은 어려운 요구 사항이며 내 답변은 서면으로 유효하지 않습니다.
하지만 이 변경으로 인해 다음이 수행되어야 합니다.
data="$(< /dev/urandom tr -dc "\t\n [:alnum:]" | dd iflag=fullblock bs=32K count=1)"
dd iflag=fullblock bs=32K count=1 of=./temp.txt <<<"${data}"
두 번째는 dd
생성된 데이터만 가져오도록 하는 것입니다. 그 사이 어딘가에서 어딘가에서 추가 바이트(암시된 줄 바꿈?)를 찾는 것처럼 보입니다 $( )
. <<<
이 문제를 해결해 드리겠습니다. 다소 번거롭다는 점은 인정합니다. 임의 데이터의 크기가 임의적이거나 중요하지 않은 경우 단순화할 수 있다고 확신합니다.