ここで必要なのは、年の範囲(1987年から2017年)を指定して6つの日付を生成するコマンドです。例えば:
12/10/1987
30/04/1998
22/02/2014
17/08/2017
19/07/2011
14/05/2004
sed
、gawk
などを使用して、それをどのように行うことができますか?
問題を、最初の可能な日付を表す数値と最後の可能な日付(実際には最後の可能な直後の日付)を表す数値の間で、UNIXエポック形式の乱数を生成することに変えることができます。それ以外はすべて、標準の日付変換によって処理されます。 gawk
はbash
(浮動小数点対15ビット整数)よりも乱数解決が優れているため、gawk
を使用します。 Rand()
の結果Nは0 <= N <1のような浮動小数点であることに注意してください。これが上限を下回る理由であり、ローリングできない制限です。結果の数のオプションの3番目のパラメーターがあります。
#!/usr/bin/gawk -f
BEGIN {
first=mktime(ARGV[1] " 01 01 00 00 00")
last=mktime(ARGV[2]+1 " 01 01 00 00 00")
if (ARGC == 4) { num=ARGV[3] } else { num=1 }
ARGC=1
range=last-first
srand(sprintf("%d%06d", systime(), PROCINFO["pid"]))
for (i=1; i <= num; i++) {
print strftime("%d/%m/%Y", range*Rand()+first)
}
}
例えば:
./randomdate.gawk 1987 2017 6
26/04/1992
28/04/2010
21/04/2005
17/02/2010
06/10/2016
04/04/1998
date
、shuf
およびxargs
の場合:
開始日と終了日を「1970-01-01 00 000:00 UTCからの秒数」に変換し、shuf
を使用してこの範囲の6つのランダムな値を出力します。この結果をxargs
にパイプし、値を目的の日付形式に変換します。
編集: 2017年の日付を出力に含める場合は、1年-1s(2017-12-31 23:59:59
)から終了日まで。 shuf -i
は、開始と終了を含む乱数を生成します。
shuf -n6 -i$(date -d '1987-01-01' '+%s')-$(date -d '2017-01-01' '+%s')\
| xargs -I{} date -d '@{}' '+%d/%m/%Y'
出力例:
07/12/1988
22/04/2012
24/09/2012
27/08/2000
19/01/2008
21/10/1994
Perl:
Perl -MTime::Piece -sE '
my $t1 = Time::Piece->strptime("$y1-01-01 00:00:00", "%Y-%m-%d %H:%M:%S");
my $t2 = Time::Piece->strptime("$y2-12-31 23:59:59", "%Y-%m-%d %H:%M:%S");
do {
my $time = $t1 + int(Rand() * ($t2 - $t1));
say $time->dmy;
} for 1..6;
' -- -y1=1987 -y2=2017
出力例:
10-01-1989
30-04-1995
10-12-1998
02-01-2016
04-06-2006
11-04-1987
以下がoneの方法で、ほとんどがawkです:
#!/bin/sh
[ "$end" -ge "$start" ] || exit 1
awk -v start=$1 -v end=$2 '
BEGIN {
srand();
for(i=1; i <= 6; i++)
printf "%02d/%02d/%d\n", 1 + Rand() * 28, 1 + Rand() * 12, start + Rand() * (end-start);
}
' < /dev/null
シェルスクリプトは2つのパラメーターを取り、それらを変数としてawkに渡します。awkは入力を読み取らず、BEGIN
ブロックですべての作業を行います。
乱数ジェネレータをシードした後、printf
ステートメントで6回ループします。そのprintステートメントは、1〜28(1月は安全)、1〜12、月、および指定された開始年と終了年の間の乱数を生成して、範囲内の可能な日付のサブセットを選択します。ランダムですが、完全にカバーされているわけではありません。29〜31日が含まれている月は表示されません。
別の方法では、GNU日付とbash機能を使用します。
#!/bin/bash
start=$1
end=$2
[[ "$start" -le "$end" ]] || exit 1
startsec=$(date -d "1/1/$start" +%s)
for((i=1; i<=6; i++))
do
r=$((RANDOM % (1 + end - start)*365*24*60*60))
date -d @$((startsec + r)) +%d/%m/%Y
done
これは、開始日の1月1日の秒以降の秒数を計算することで機能します。次に、ループごとに、追加するオフセット秒数をランダムに指定します。乱数は、指定された範囲にわたる秒数に制限されます。 GNU date次に、その日付を目的の形式に操作します。
年数の差が約90未満の場合は、$RANDOM
bashの変数を使用して、日数でオフセットを指定し、date
コマンドの制限された機能を使用して計算を実行します。
#!/bin/bash
s=$(date +%s -d "1/1/$1") # start in seconds since 1 Jan 1970
e=$(date +%s -d "1/1/$(($2+1))") # start of end year +1 in seconds
days=$(((e-s)/(24*3600))) # number of days from start to end
factor=$((32767/$days)) # RANDOM is 0 to 32767. See how many
toobig=$(($factor*$days)) # exact multiples of days.
# if RANDOM is too large, draw again
for((i=0;i<${3:-1};i++)) # produce $3 random dates
do
r=$RANDOM # find a random number < toobig
while (( r >= toobig )) # if toobig, then loop.
do r=$RANDOM
done
offset=$(($r/$factor)) # get (0,days) from (0,factor*days)
# output horrible day/month/year for N days past start date
date -d "$offset days 1/1/$1" +%d/%m/%Y
done
乱数を選択する内部ループは、バイアスを修正しようとします。乱数ソースが0、1、2、3、4、5、6、7、8、または9を等しく与えることができ、0と3の間の乱数が必要な場合、ソースから0または1を取得する場合2または3の場合は0を報告し、1または4の場合は2を報告し、6または7の場合は3を報告し、8または9の場合はソースからのこの数を無視します。 。