1

I'm wanting to prepend the epoch time to a single line of arguments. My desired output is:

$ echo foo bar baz | some_bash_awk_sed_date_program_or_something_else
1491146539 foo bar baz

The actual output I'm getting can be seen below:

$ echo foo bar baz | awk -f time_stamper.awk
1491146539
0 foo bar baz

My time_stamper.awk:

BEGIN { 
OFS=" "
printf "%s ", system("date +'%s'")
}
{ print }

I think the leading 0 is coming from the return value from date +'%s'. I was expecting setting the OFS=" " would at least return 1491146539 0 foo bar baz changing the newline to space.

Some questions about my current attempt:

  • What is wrong with my usage of the OFS built-in variable?
  • Why is the 0 printing in front of foo bar baz?

More importantly, I'm not sure if awk is the right tool for the job. Maybe I should use sed, date or some other utility.

  • How do I print the desired output?

Note: This question is more specific and therefore different from this question. Also, the answer requires the installation of moreutils which seems like an interesting addition the Unix toolset; however, I'd rather stick with more traditional Unix utilities to perform my task.

mbigras
  • 3,100

3 Answers3

5

The system() function in awk run the command and return its status. You got 0 because the command is success. The output of date +'%s' was printed separately.

To get the output of external command, you would use getline():

$ echo foo bar baz | awk '{"date +%s" | getline d; printf "%s %s\n", d, $0}'
1491147643 foo bar baz

There's nothing to do with OFS, because it's a space by default.


With gawk or mawk, you can also do:

echo foo bar baz | gawk '{printf "%s %s\n", systime(), $0}'

The systime() return the number of seconds since epoch, not counting leap seconds


IOW, you can do it alone with date:

date +'%s foo bar baz'
cuonglm
  • 153,898
2

Bash
Here we use a while loop to ingest the arguments from stdin & perform NO splitting since we use IFS= with the read. This enables the entire line with the concomitant whitespace to be preserved. And finally, we echo the timestamp along with the arguments now available via the $l variable. A point to be kept in mind is that all arguments to echo need to be quoted for predictable behavior of the code.

echo 'foo     bar baz' | while IFS= read -r l; do echo "$(date +'%s')" "$l"; done

Perl

-n option instructs Perl to read a file line-by-line + not to print unless specifically asked to. Each line read in is stored in the $_ which is equivalent to $0 of awk. time() is a Perl builtin function to give us the epoch time. Then we put the epoch time and the current line in an anonymous array reference [ ..., ... ] and get back the contents of this array by dereferencing it, @{ ... } The double quotes "..." around the @{...} expression ensure that the list elements shall be space separated. Then we print them.

echo ... |  perl -ne 'print "@{[+time,$_]}"'

IFS= read -r l <<<"$(echo 'foo    bar baz')"
printf '%d %s\n' "$(date +'%s')" "$l"
1

This can also be done with sed as

Code:

 echo 1 2 3 | sed 's/^/'`date +"%s"`' /'

Results:

1491148928 1 2 3