시뮬레이션된 데이터를 사용하여 CSV를 생성하려고 합니다.
for i in {1..1000000..1}
do
echo "$i,$(date -d "2017-08-01 + $(shuf -i 1-31 -n 1) days" +'%Y-%m-%d')" >> $F
done;
1에서 백만까지 반복하고 고유 ID 및 생성무작위의날짜
하지만 매우 느리게 실행됩니다. 평행하게 만들 수 있는 단일 선이 있습니까?
답변1
마지막에 최종 결과를 확인하세요.
for i in {1..1000000..1}
do
echo "$i,$(date -d "2017-08-01 + $(shuf -i 1-31 -n 1) days" +'%Y-%m-%d')" >> $F
done;
셸 루프는 느리며 이 특정 루프를 특히 느리게 만드는 두 가지 주요 요인이 있습니다.
- 반복할 때마다 파일을 열고 추가합니다.
- 외부 유틸리티(
shuf
and)는 각 반복에서 두 번 실행됩니다.date
이는echo
아마도 쉘에 내장되어 있으므로 오버헤드가 덜 발생합니다.
출력 리디렉션은 해결하기 가장 쉽습니다.
for i in {1..1000000..1}
do
echo "$i,$(date -d "2017-08-01 + $(shuf -i 1-31 -n 1) days" +'%Y-%m-%d')"
done >"$F"
그러면 출력 파일이 한 번만 열리고 루프 중에 열린 상태로 유지됩니다.
나머지 코드는 awk
GNU를 사용하여 더 효율적으로 수행 할 수 있습니다 date
(사용하고 있으므로 shuf
Linux 시스템을 사용하고 있다고 가정하므로 date
실제로는 GNU일 가능성이 높습니다 date
).
awk 'END { for (i=0;i<100;++i) { printf("2017-08-01 + %d days\n", 1+int(31*rand())) }}' /dev/null
그러면 다음과 같은 100줄이 생성됩니다.
2017-08-01 + 22 days
2017-08-01 + 31 days
2017-08-01 + 11 days
2017-08-01 + 27 days
2017-08-01 + 27 days
2017-08-01 + 20 days
(etc.)
이것을 GNU로 가져오자 date
. GNU에는 프로그램 이 출력하는 날짜 사양 과 같은 여러 날짜 사양을 일괄 입력할 수 있는 date
플래그가 있습니다 .-f
awk
awk 'END { for (i=0;i<100;++i) { printf("2017-08-01 + %d days\n", 1+int(31*rand())) }}' /dev/null |
date -f - +'%Y-%m-%d'
이제 우리는 얻습니다
2017-08-23
2017-08-27
2017-08-21
2017-08-29
2017-08-25
2017-08-17
2017-08-07
(etc.)
그런 다음 각 행에 고유 ID(연속된 정수)를 추가하면 됩니다.
awk 'END { for (i=0;i<100;++i) { printf("2017-08-01 + %d days\n", 1+int(31*rand())) }}' /dev/null |
date -f - +'%Y-%m-%d' |
awk -vOFS=',' '{ print NR, $0 }'
이건 널위한거야
1,2017-08-06
2,2017-08-17
3,2017-08-25
4,2017-08-28
5,2017-08-14
6,2017-08-15
7,2017-08-17
8,2017-08-10
9,2017-08-16
10,2017-08-08
(etc.)
이제 끝났습니다. 그 과정에서 나는 쉘 루프가 있다는 사실을 완전히 잊어버렸습니다. 필요하지 않은 것으로 밝혀졌습니다.
100
원하는 값으로 설정 하고 필요에 맞게 난수 생성기를 조정하세요. rand()
0 <= 숫자 < 1이 되는 부동 소수점 값을 반환합니다.
분명히, 8월(31일로 구성된 달)에 임의의 날짜를 원하는 경우 date
완전히 우회할 수 있습니다.
awk 'END { for (i=1;i<=100;++i) { printf("%d,2017-08-%02d\n", i, 1+int(31*rand())) }}' /dev/null
BSD가 아닌 GNU awk
및 Mike의 awk
( )를 사용하면 다음에서 직접 올바른 날짜 처리를 수행할 수도 있습니다 .mawk
awk
awk
awk 'END { for (i=1;i<=100;++i) { printf("%d,%s\n", i, strftime("%Y-%m-%d", 1501545600 + int(2678400*rand()),1 )) }}' /dev/null
이제 우리는 날짜 대신 Unix 타임스탬프를 다루고 있습니다. 1501545600은 "2017년 8월 1일 화요일 00:00:00 UTC"에 해당하며, 이는 31일 동안 2678400초입니다.
답변2
# A "random" date between 2000-01-01 and 2025-12-28
# Only uses day 01 to 28
rand_date() {
printf "%4d-%02d-%02d" $((RANDOM%25+2000)) $((RANDOM%12+1)) $((RANDOM%28+1))
}
csv_data() {
for ((i=1; i<="$1"; i++)); do printf "%d,%s\n" $i $(rand_date); done
}
$ time (csv_data 1000000 > data.csv)
real 7m26.683s
user 0m36.376s
sys 1m57.768s
Perl이 더 빠를 수도 있습니다. 시도해 보겠습니다.
$ cat data.pl
#!/usr/bin/perl
$, = ",";
$\ = "\n";
sub rand_date {
sprintf "%4d-%02d-%02d", int(rand(25))+2000, int(rand(12))+1, int(rand(28))+1;
}
sub csv_data {
my $n = shift;
for ($i = 1; $i <= $n; $i++) {
print $i, rand_date();
}
}
csv_data(1_000_000);
$ time (perl data.pl > data.csv)
real 0m0.881s
user 0m0.876s
sys 0m0.004s
응, 더 빨리...