Transform an entire column using "date" command - linux

Here is a dummy CSV file with 3 rows. The actual file has 7 million rows.
testdates.csv:
y_m_d
1997-01-01
1985-06-09
1943-07-14
The date tool can usually be formatted as such , to get the 'day' :
date -d "25 JUN 2011" +%A
=> output: Saturday
Query: How to provide an entire column as input for the date +%A transformation?
The resulting output should be appended to the end of the input file.
Intended output:
y_m_d, Day
1997-01-01, Thursday
1985-06-09, Sunday
1943-07-14, Tuesday

To read multiples dates from a file using GNU date, you can use the -f/--file option:
$ date -f testdates.csv '+%F, %A'
1997-01-01, Wednesday
1985-06-09, Sunday
1943-07-14, Wednesday
Since your file has a header row, we have to skip that, for example using process substitution and sed:
date -f <(sed '1d' testdates.csv) '+%F, %A'
To get your desired output, combine like this:
echo 'y_m_d, Day'
date -f <(sed '1d' testdates.csv) '+%F, %A'
or write to a new file:
{
echo 'y_m_d, Day'
date -f <(sed '1d' testdates.csv) '+%F, %A'
} > testdates.csv.tmp
and after inspection, you can rename with
mv testdates.csv.tmp testdates.csv

Hard to beat that date answer.
GNU awk would be OK too:
gawk -v OFS=', ' '
NR == 1 {$2 = "Day"}
NR > 1 {$2 = strftime("%A", mktime(gensub(/-/, " ", "g", $1) " 0 0 0"))}
1
' testdates.csv
y_m_d, Day
1997-01-01, Wednesday
1985-06-09, Sunday
1943-07-14, Wednesday
Or perl:
perl -MTime::Piece -lne '
print "$_, ", $. == 1
? "Day"
: Time::Piece->strptime($_, "%Y-%m-%d")->strftime("%A")
' testdates.csv

#/bin/bash
while read datespec; do
echo $datespec, $(date -d "$datespec" +%A)
done < testdates.csv
Output:
1997-01-01, Wednesday
1985-06-09, Sunday
1943-07-14, Wednesday

Related

bash is eating spaces from date format in linux

date format shows correct when i execute just date but when I store in a variable, loosing a space in date if it has single digit(need that extra space to grep /var/log/messages). please suggest to get the exact format as it is. thanks!
$date -d '-1 day' '+%b %e'
Aug 1
$echo $(date -d '-1 day' '+%b %e')
Aug 1
$var=`date -d '-1 day' '+%b %e'`
$echo $var
Aug 1
Use double-quotes like this:
$ echo $(date -d '+1 day' '+%b %e')
Aug 2
$ echo "$(date -d '+1 day' '+%b %e')"
Aug 2
Or:
$ var="$(date -d '+1 day' '+%b %e')"
$ echo $var
Aug 2
$ echo "$var"
Aug 2
Without double-quotes, the shell, among other things, applies word splitting to the output and that collapses multiple spaces to one blank.

print time in double decimal shell script

how can I print output in double decimal.
below command will print hour in GMT format but i want output as 06 and for double digit hour it should be 10,11,12.
date -u --date="today" +"%I" | awk -F' ' '{print $1-1}'
6
You may use printf "%02d" in awk to achieve it,
$ date -u --date="today" +"%I" | awk -F' ' '{printf "%02d\n",$1-1}'
06
Perhaps you want:
date -u --date="- 1 hour" +"%I"`
If the time adjustment is part of your date string, the format will not be munged.
Alternately, if what you really want is a way to zero-pad a number in bash or awk, you have a variety of alternatives:
date -u --date="- 1 hour" +"%I" | awk '{printf "%02d\n",$1-1}'
Or in bash alone:
read hour < <( date -u --date="- 1 hour" +"%I" )
printf '%02d\n' "$hour"
Get the idea? Output format happens when you print your output, and printf in whatever language formats your output.
awk is superfluous here. You can use a relative time format with date:
date -u --date="-1 hour" +"%I"
06

UNIX: How do I output data from 2 files using a loop structure?

Good afternoon everyone, I have a project I am working on, but I am having a bit of trouble with it. I am supposed to create a script that uses a loop structure to output data from 2 data files.
These are the two data files:
data1:
Dave,7348389800
Bob,3131234567
Carol,2483445576
Mary,3134491390
Ted,2484962204
Alice,6165564458
data2:
Bob,tuesday
Carol,friday
Ted,sunday
Alice,wednesday
Dave,thursday
Mary,saturday
This is how it is supposed look when i display it:
Day Name Phone
__________________________________________
MONDAY Nobody
TUESDAY Bob (313) 123-4567
WEDNESDAY Alice (616) 556-4458
THURSDAY Dave (734) 838-9800
FRIDAY Carol (248) 344-5576
SATURDAY Mary (313) 449-1390
SUNDAY Ted (248) 496-2204
This is my current code:
#!/bin/ksh
for day in monday tuesday wednesday thursday friday saturday sunday
do
day=`grep -i day data2 |cut -d "," -f 2 `
name=`cut -d "," -f 1 data1 `
phone=`cut -d "," -f 2 data1`
done
echo $day $name $phone >>output
And this is the output I am getting:
Day Name Phone
==============
tuesday friday sunday wednesday thursday saturday Dave Bob Carol Mary Ted Alice 7348389800 3131234567 2483445576 3134491390 2484962204 6165564458
Any help would be greatly appreciated!
This works, using printf to get neatly formatted columnar output:
format="%-9s %-9s %s\n"
printf "$format" Day Name Phone
printf "$format" Day Name Phone | sed 's/./-/g'
for day in monday tuesday wednesday thursday friday saturday sunday
do
who=$(grep -i "$day" data2 | cut -d "," -f 1)
if [ -z "$who" ]
then
who="NOBODY"
phone=""
else
phone=$(grep -i "$who" data1 | sed 's/^[^,]*,\(...\)\(...\)\(....\)/(\1) \2-\3/')
fi
printf "$format" $(echo "$day" | tr 'a-z' 'A-Z') "$who" "$phone"
done
You could investigate typeset -u uday="$day" and then pass "$uday" to the printf; that doesn't seem to be an option in Bash 3.x, but it works in Korn shell and in Bash 4.x (for big enough values of x). […Thinking about it, the grep | cut and grep | sed sequences could (and probably should) be replaced by pure sed, which is tidier still. You could also avoid the repeated printf to deal with the heading by using sed 'p;s/./-/g'. Fixing those issues is left as an exercise for the reader…]
Output:
Day Name Phone
---------------------------
MONDAY NOBODY
TUESDAY Bob (313) 123-4567
WEDNESDAY Alice (616) 556-4458
THURSDAY Dave (734) 838-9800
FRIDAY Carol (248) 344-5576
SATURDAY Mary (313) 449-1390
SUNDAY Ted (248) 496-2204
awk to the rescue!
$ awk -F, -vOFS="\t" '
BEGIN{split("1monday 2tuesday 3wednesday 4thursday 5friday 6saturday 7sunday",days," ")}
NR==FNR{a[$1]=$2;next} {b[$2]=$1}
END{for(i in days) {
d=substr(days[i],2,length(days[i])-1);
dp=toupper(days[i]);
if(b[d])
print dp,b[d],a[b[d]];
else
print dp,"Nobody"}}' data1 data2
| sort | cut -c2- | column -t
| sed -r 's/([0-9]{3})([0-9]{3})([0-9]{4}$)/(\1) \2-\3/'
MONDAY Nobody
TUESDAY Bob (313) 123-4567
WEDNESDAY Alice (616) 556-4458
THURSDAY Dave (734) 838-9800
FRIDAY Carol (248) 344-5576
SATURDAY Mary (313) 449-1390
SUNDAY Ted (248) 496-2204

Sort files based on day of week

I have several files:
Friday.log
Monday.log
Tuesday.log
Saturday.log
Sunday.log
Thursday.log
Tuesday.log
Wednesday.log
I want to put their filename without .log and contents into one file but in order of day of week starting with Monday to Sunday. I have a command that will put them together without .log but not in order:
awk 'FNR==1{sub(/[.][^.]*$/"", FILENAME); print FILENAME} 1' *.log > all.log
That gives me :
Friday
... Friday contents
Monday
... Monday contents
Tuesday
... Tuesday contents
Saturday
... Saturday contents
Any idea?
You can "play" with the %u parameter of date to know the day of the week of any given date:
$ date -d"last Sunday" +%u
7
However, and since this list is pretty much stable, why don't you just hardcode it in an array?
#!/bin/bash
days=('Monday' 'Tuesday' 'Wednesday' 'Thursday' 'Friday' 'Saturday' 'Sunday')
for day in "${days[#]}"
do
echo "$day"
cat "$day.log"
done > all.log
Perl solution:
perl -le 'for $day qw(Monday Tuesday Wednesday Thursday Friday Saturday Sunday) {print $day; system("cat $day.log")}'
I ended up just doing:
touch Thursday.log && touch Wednesday.log && touch Tuesday.log && touch Monday.log && ls -t | xargs -i awk 'FNR==1{sub(/[.][^.]*$/"", FILENAME); print FILENAME} 1' {} > all.log

Configuring date command to meet my format

I have a date in YYYY.MM.DD HH:SS format (e.g. 2014.02.14 13:30). I'd like to convert it in seconds since epoch using the date command.
The command
date -d"2014.02.14 13:30" +%s
won't work, because of the dots separation.
Any Ideas?
Why don't you make the date format acceptable? Just replace dots with dashes:
$ date --date="`echo '2014.02.14 13:30' | sed 's/\./-/g'`" +%s
1392370200
Here I first change the format:
$ echo '2014.02.14 13:30' | sed 's/\./-/g'
2014-02-14 13:30
and then use the result as a parameter for date.
Note that the result depends on your timezone.
You can use:
s='2014.02.14 13:30'
date -d "${s//./}"
Fri Feb 14 13:30:00 EST 2014
To get EPOCH value:
date -d "${s//./}" '+%s'
1392402600
using awk :
s=`echo "2014.02.14 13:30" | awk '{gsub(/\./,"-",$0);print $0}'`
echo -d "$s"
date -d "$s" +%s
output:
Fri Feb 14 13:30:00 IST 2014
1392364800
Perl: does not require you to munge the string
d="2014.02.14 13:30"
epoch_time=$(perl -MTime::Piece -E 'say Time::Piece->strptime(shift, "%Y.%m.%d %H:%M")->epoch' "$d")
echo $epoch_time
1392384600
Timezone: Canada/Eastern
I Finally solved it using
awk 'BEGIN{FS=","}{ gsub(/./," ",$1);gsub(/:/," ",$2); var=sprintf("%s %s 00",$1,$2); print mktime(var), $3,$4,$5,$6,$7 }' myfile | less
so myfile:
2014.09.24,15:15,1.27921,1.27933,1.279,1.27924,234
became
1411582500 1.27921 1.27933 1.279 1.27924 234
:)

Resources