3

I have a rather simple script (print content from a tty after adding timestamp to every row). It outputs nicely on the command line, but redirecting the output with > does not work. Why not?

Here is the script:

#!/bin/bash
awk '{ print strftime("%Y-%m-%d %H:%M:%S |"), $0; }' "$1"

Running it as is, like timecat /dev/ttyACM0 works fine, I see the content in my terminal.

But if I run timecat /dev/ttyACM0 > ~/tmp.log, nothing comes out. Same with tee. The file is there, but it is empty.

Is there something weird with awk in the script, how can I modify this to make the redirection work?

Charles Duffy
  • 280,126
  • 43
  • 390
  • 441
Gauthier
  • 40,309
  • 11
  • 63
  • 97
  • Unrelated to your question, `[[ $@ == -h ]]` isn't reliable. You can't compare a *list* to a *single item* and expect good results -- the shell will either flatten your list into a string (resulting in an incorrect comparison result -- f/e, `ls --help whatever` still prints help, but the code above won't because it's treating `"--help whatever"` as a single string), or pass the items it contains individually (resulting in a syntax error). – Charles Duffy Jan 30 '19 at 22:26
  • Anyhow, if you want to know what's happening at runtime, a very good place to start is running with trace logging enabled. `bash -x timecat /dev/ttyACM0 >~/tmp.log` will emit a trace of your script's execution to stderr so you can figure out what's going on. That should help you simplify the question to have a [mcve] with no code unrelated to producing the narrow behavior at hand. Adding that log as part of the question would also enable answers with less guesswork involved. – Charles Duffy Jan 30 '19 at 22:28
  • (As another aside, the code as written is going to fall down when the `tty` variable is empty, potentially in misleading ways; if you quote all variable references, using `"$tty"` instead of `$tty`, the value will still be passed through, generally resulting in more meaningful and helpful error messages. Consider using http://shellcheck.net/ to catch such issues as a matter of practice). – Charles Duffy Jan 30 '19 at 22:29
  • **Oh**. Are you trying to check the output (or monitor results from `tee`) while the script still runs, instead of letting the script exit (or collect at least ~32kb or so of content, typically enough to trigger a flush) before checking if you have a non-empty output file? If that's the case, you're probably just being bitten by buffering, which would make this a duplicate of the many, many SO questions covering ground already trod by [BashFAQ #9](https://mywiki.wooledge.org/BashFAQ/009). – Charles Duffy Jan 30 '19 at 22:31
  • see also f/e [How do you pipe input through grep to another utility?](https://stackoverflow.com/questions/972370/how-do-you-pipe-input-through-grep-to-another-utility) -- different tool, same problem. – Charles Duffy Jan 30 '19 at 22:34
  • @CharlesDuffy Right on the money about buffering. The worst is that I don't think it's the first time I get bitten. Somehow, my searches didn't find the duplicates. Thanks a lot for all the tips, I really need to practice bash hygiene. – Gauthier Jan 30 '19 at 22:39
  • Editing to narrow the question on awk, which is the part that distinguishes it from several of the other entries in the knowledgebase (at least, the ones I've found so far). – Charles Duffy Jan 30 '19 at 22:45
  • 1
    ...okay, after looking further, https://stackoverflow.com/questions/8058831/awk-not-printing-to-file actually appears to be an exact duplicate (including `fflush()` as a suggestion in the accepted answer). – Charles Duffy Jan 30 '19 at 22:48

1 Answers1

8

All this needed was to flush the print within the command, replacing the last script row with this:

awk '{ print strftime("%Y-%m-%d %H:%M:%S |"), $0; fflush(); }' $tty
                                                  ^^^^^^^^^
Gauthier
  • 40,309
  • 11
  • 63
  • 97
  • I am developing a bash script with calls to functions in an awk program file; most calls with awk -f prgfile < input > output; which worked on 5 calls; not on the 6th. I run the line in the terminal and it works... in the bash script it doesn't. Spent 3 hours comparing file name strings... then googled and found this post. This worked for me! – MaxG May 12 '20 at 07:55