Passing date command into a variable?
The reason I am doing this is a would like 4 random digits to play with (Random numbers). I have produced this bash script to show an example.
1622001937610 1622001938249 1622001938758 1622001939267 1622001939774 1622001940282 1622001940790 1622001941299 1622001941807 1622001942315 1622001942823
Now I wanted to add the results of just one instance of this into an array, index from the last 9th digit to receive 4 random digits based on nano second time. How ever I don’t seem to have full grasped the syntax used within bash to achieve the result. Could I possible call date +%s%N)/1000000 straight into an array? As my idea was to create and empty array and then just append the result into the array, and index from the 9th number. And pass the result into a second variable from there I can work on. Just learning to turn the result of date +%s%N)/1000000 into a variable would be of great help. Sorry to be a pain. Any thank you in advanced.
If you do $((ns / 1000000)) , you drop off the six rightmost digits, that is the micro- and nanoseconds, leaving a millisecond timestamp, which isn’t that random. E.g. if we look at the output you have, the three last digits alternate between 2xx and 7xx for a while until it drifts to 3xx and 8xx . You could use $(( ns % 1000000 )) to take the remainder instead, keeping the six lowest-order digits, but then the clock granularity might not be good enough for all of those to be meaningful either.
3 Answers 3
My initial approach was to use string processing for the date output to get your required values. The version here uses maths processing (divide by 1000000, modulo 10000) but I’ve left the alternative commented for you
#!/bin/bash items=() random=$(( ($(date +%s%N) / 1000000) % 10000 )) # Second and milliseconds # random=$( date +%s%N | grep -oP '. (?=. $)' ) items+=($random) # Append value to array echo "$" # First array value echo "$" # Last (most recently appended) value declare -p items # Visual inspection of array elements
You can use the $ parameter expansion syntax to extract a substring of a value:
$ nanoseconds=$(date +%N) $ printf '%s\n' "$nanoseconds" "$" 785455000 5455
Or, as suggested, using /dev/urandom:
Reading that into an array, using the bash mapfile command:
If you run date +%s%N , the output looks something like this:
1622046533072036066 ssssssssssmmmuuunnn
with the right-hand digits indicating the smaller units. ( m / u / n for milli-/micro-/nanoseconds.)
If you the divide that by 1000000, as $(( . / 1000000)) does, you remove the six rightmost digits, leaving only the seconds and milliseconds.
Those are not very random. E.g. in your test run, the consecutive output numbers increase by a somewhat consistent 508, which in milliseconds closely matches the 0.5 seconds you asked for.
You’d likely get more random values if you instead kept the rightmost digits, and dropped the leading ones, e.g. with the modulo operator, $(( . % 1000000)) . Though it’s possible that the lowest digits aren’t very random either, if the system doesn’t have clocks with a fine enough granularity.
If you keep only the low digits, you don’t really need to have date output the full seconds, but could instead use just +%N , except that the nanoseconds value is always zero-padded to 9 digits, and Bash treats numbers starting with zeroes as octal, so e.g. 092345678 would produce an error. Adding an extra digit to the front would prevent that, but so does adding the seconds value.
On my system, the difference between the values from consecutive iterations of the following loop was roughly in the range of 1470000 to 1560000 ns, (~ 1.5 ms / iteration) so I probably wouldn’t use more than four of the rightmost digits.
#/bin/bash array=() prev=$(date +%s%N) for ((i=0; i < 100; i++)); do this=$(date +%s%N) # diff=$(( (this - prev) % 1000000000)) diff=$(( (this - prev) % 10000)) printf "$prev $this %04d\n" "$diff" array+=("$diff") prev=$this done
Instead of arithmetic, one could just treat the output from date as a string, and chop some characters off. This would leave the last 4 characters:
Then again, one could consider other ways to produce random numbers, e.g. shuf from GNU coreutils, which isn't limited to just shuffling, but can also pick values with repetition. E.g. this would print 20 numbers, 4 digits each:
or with some hoops to get zero-padding:
shuf -i 10000-19999 -r -n 20 |sed -e 's/^1//'
You can read the output to an array with readarray :
Not surprisingly, shuf is hideously faster than looping in the shell over calls to date . You could also use a smaller range, e.g. -i 0-9 to get single-digit numbers.
Current time/date as a variable in BASH and stopping a program with a script
I don't get how it works bc it's before o the output of raspistil and in quotes. Thank you all in advance.
found the forum I lifted that code from, it's this one. unix.stackexchange.com/questions/57590/… toward the bottom VVV
4 Answers 4
or, using more modern syntax,
the variable NOW will be set to the output of the date command at the time when that line is executed. If you do this in ~/.bashrc , then $NOW will be a timestamp that tells you when you started the current interactive shell session.
You could also set the variable's value with
if you're using bash release 4.2 or later. This prints the timestamp directly into the variable without calling date .
In the script that you are showing, the variable NOW is being set when the script is run (this is what you want).
is carried out, the shell will expand the variable in the string. It does this even though it is in double quotes. Single quotes stops the shell from expanding embedded variables (this is not what you want in this case).
Note that you don't seem to actually use the filename variable in the call to raspistill though, so I'm not certain why you set its value, unless you just want it outputted by echo at the end.
In the rest of the code, you should double quote the $NOW variable expansion (and $filename ). If you don't, and later change how you define NOW so that it includes spaces or wildcards (filename globbing patterns), the commands that use $NOW may fail to parse their command line properly.
string="hello * there" printf 'the string is "%s"\n' $string
string="hello * there" printf 'the string is "%s"\n' "$string"
In a unix shell, how to get yesterday's date into a variable?
How would i go about getting yesterdays date into a variable? Basically what i'm trying to achieve is to use grep to pull all of yesterday's lines from a log file, since each line in the log contains the date in "Mon 01/02/2010" format. Thanks a lot
17 Answers 17
dt=$(date --date yesterday "+%a %d/%m/%Y") echo $dt
+1 for answering the question precisely. Caveat is that the -yesterday flag may not be supported on posters version of unix
This is the best answer among all the others, short, sweet, easy, handy, cool and it proves the story 'Give a man a fish he is fed for a day, but teach him to fish, he is fed for life'
You can use GNU date command as shown below
Getting Date In the Past
To get yesterday and earlier day in the past use string day ago:
Getting Date In the Future
To get tomorrow and day after tomorrow (tomorrow+N) use day word to get date in the future as follows:
If you have Perl available (and your date doesn't have nice features like yesterday ), you can use:
pax> date Thu Aug 18 19:29:49 XYZ 2010 pax> dt=$(perl -e 'use POSIX;print strftime "%d/%m/%Y%",localtime time-86400;') pax> echo $dt 17/08/2010
@Chris: note that this gives you the date 24 hours ago, which is subtly different from yesterday's date. If your locale has daylight savings time, this will give the wrong date after 23:00 on the first day of winter time.
@Gilles, that's not a bad point since I'm using locattime. If you're concerned about it, you can check if the hour is greater than 6pm, just subtract 6 hours. That should hopefully cover it.
If you are on a Mac or BSD or something else without the --date option, you can use:
date -r `expr \`date +%s\` - 86400` '+%a %d/%m/%Y'
date -r $((`date +%s` - 86400)) '+%a %d/%m/%Y'
+1 just for not assuming that every UNIX question is on Linux. Some of us have to work with other styles as well.
@paxdiablo: agreed, but if no specific info is given than I personally assume that the GNU toolkit is an option 😉 The differences between HP-UX , AIX , Solaris and *BSD are simply to great to guess the flavour.
$(( for arithmetic expansion is nice, but not what @bstpierre was talking about. Even inside there, you should really be using $( . ) for the command expansion: $(( $(date +%s) - 86400 )) .
I have shell script in Linux and following code worked for me:
#!/bin/bash yesterday=`TZ=EST+24 date +%Y%m%d` # Yesterday is a variable mkdir $yesterday # creates a directory with YYYYMMDD format
TZ is time zone, EST+24 gives yesterday's date for Eastern Standard time (like wise you can use EST-24 for tomorrow's date) +%Y%m%d is the format for YYYYMMDD.
This is by far the most succinct version that works on AIX for anyone who is searching for such an answer. AIX doesn't allow for the -r or -d flags but does in fact allow manipulating the time zone like this! You've made my day I've been trying to figure this out for like two hours, I'm making a date appear as half a year ago and the other ideas weren't working.
dt=`case "$OSTYPE" in darwin*) date -v-1d "+%s"; ;; *) date -d "1 days ago" "+%s"; esac` echo $dt
It works on both Linux and OSX.
You have atleast 2 options
perl -e '@T=localtime(time-86400);printf("%02d/%02d/%02d",$T[4]+1,$T[3],$T[5]+1900)'
date --date yesterday "+%a %d/%m/%Y" | read dt echo $
@Chris: I assumed it wouldn't be a GNU compatible date but since you didn't specify the Unix variant I simply guessed 😉 With HP-UX your options are a little more limited, date doesn't have these options so Perl might be the best option.
Not that it matters but you don't need to add 1900 to the year if you're then going to %100 the result 🙂
@paxdiablo: fair point, Perl is obviously not one of my strong points 😉 I'll +1 your answer instead.
Here is a ksh script to calculate the previous date of the first argument, tested on Solaris 10.
#!/bin/ksh sep="" today=$(date '+%Y%m%d') today=$ ty=`echo $today|cut -b1-4` # today year tm=`echo $today|cut -b5-6` # today month td=`echo $today|cut -b7-8` # today day yy=0 # yesterday year ym=0 # yesterday month yd=0 # yesterday day if [ td -gt 1 ]; then # today is not first of month let yy=ty # same year let ym=tm # same month let yd=td-1 # previous day else # today is first of month if [ tm -gt 1 ]; then # today is not first of year let yy=ty # same year let ym=tm-1 # previous month if [ ym -eq 1 -o ym -eq 3 -o ym -eq 5 -o ym -eq 7 -o ym -eq 8 -o ym - eq 10 -o ym -eq 12 ]; then let yd=31 fi if [ ym -eq 4 -o ym -eq 6 -o ym -eq 9 -o ym -eq 11 ]; then let yd=30 fi if [ ym -eq 2 ]; then # shit. :) if [ ty%4 -eq 0 ]; then if [ ty%100 -eq 0 ]; then if [ ty%400 -eq 0 ]; then #echo divisible by 4, by 100, by 400 leap=1 else #echo divisible by 4, by 100, not by 400 leap=0 fi else #echo divisible by 4, not by 100 leap=1 fi else #echo not divisible by 4 leap=0 # not divisible by four fi let yd=28+leap fi else # today is first of year # yesterday was 31-12-yy let yy=ty-1 # previous year let ym=12 let yd=31 fi fi printf "%4d$%02d$%02d\n" $yy $ym $yd
Tests
bin$ for date in 20110902 20110901 20110812 20110801 20110301 20100301 20080301 21000301 20000301 20000101 ; do yesterday $date; done 20110901 20110831 20110811 20110731 20110228 20100228 20080229 21000228 20000229 19991231