44 comments

[ 2.8 ms ] story [ 93.7 ms ] thread
Two comments:

1) Really? This is on the front page of HN?

2) why aren't you printing to stderr?

Its Sunday, frontpage tends to be quite dead.

(No idea why not stderr however)

1) Slow news day ... and this being an example of read's -t option put to a good use.

2) Ah, pedantic nitpicking, love it. Because the script is meant for interactive use with no streams redirected off the terminal, and because it doesn't output diagnostics or errors, but rather augments the stdout.

Or put differently - show me an example where writing into stderr would make more sense.

(edit) I guess someone can tee the output afterwards. Fine, I'll make it use stderr.

One argument against using stderr: IIRC stdout defaults to line buffering (or more if piped), while stderr is flushed immediately, so using stderr vs. stdout can yield different results.
Hey, I can envisage this being helpful. Thanks. One criticism, which I think has already been voiced, is that you you print to standard error instead of standard out. That way anyone piping to a file won't be surprised when things break if the file is read by something else.
huhsamovar, you are shadowbanned.
Hm, curious. Well, it seems at least you saw my feedback.
Another alternative is 'ts' which is part of joey hess's awesome collection of unix tools, moreutils.[1] I did not find out about ts until too late so I am still in the habit of using tai64n from djb's daemontools, which adds a tai64 timestamp to every file[2] and then tai64nlocal[3] in order to convert the timestamps to something useful to humans.

If you don't know about moreutils check out the collection. I don't know what I'd do without vipe or vidir:

  Chronic: runs a command quietly unless it fails
  combine: combine the lines in two files using boolean operations
  ifdata: get network interface info without parsing ifconfi
  ifne: run a program if the standard input is not empty
  isutf8: check if a file or standard input is utf-8
  lckdo: execute a program with a lock held
  mispipe: pipe two commands, returning the exit status of
  parallel: run multiple jobs at once
  pee: tee standard input to pipes
  sponge: soak up standard input and write to a file
  ts: timestamp standard input
  vidir: edit a directory in your text editor
  vipe: insert a text editor into a pipe
  zrun: automatically uncompress arguments to command
[1] http://joeyh.name/code/moreutils/

[2] http://cr.yp.to/daemontools/tai64n.html

[3] http://cr.yp.to/daemontools/tai64nlocal.html

If I read ts source right, it merely prepends the current time to every line it echoes from stdin to stdout.

now is different. It re-prints current time once a second while waiting for the input. You basically get the running clock at the last line of output.

Oops. You are correct. Thanks for pointing that out. I have to say that now that I understand what it does I have no idea about the use case.
One slightly off-topic note:

> ifdata: get network interface info without parsing ifconfi

If it's Linux, ifconfig isn't maintained anymore and might actually be lying (eg, virtual IPs on vlans on bonded NICs - sounds exotic but almost every trading house uses this config). Use the 'ip' command for most things you would have done with 'ifconfig'.

If it's BSD, ignore that and ifconfig away.

Thank god for the Linux people innovating and replacing a perfectly functional tool that could be properly extended to add support for that configuration, and instead requiring people to learn yet another command.

It's about as bad as Solaris with their ifconfig/ipadm stuff and changing everything around so that configuration exists in multiple places and one tool doesn't handle the other. ipadm doesn't properly deal with /etc/<hostname>.<interface> files and the two will conflict. Ugh.

Judging by the amount of righteous sarcasm dripping from your comment you clearly have no idea what ip is.
> sponge: soak up standard input and write to a file

Whoa! No kidding? I wrote a program years ago, probably around 2005, also called sponge, that does exactly this[1].

I'm not sure how to feel about this. Obviously the idea was a good one, but it's equally obvious I suck at getting the word out about my creations.

[1] https://github.com/graue/graue-utils/blob/master/sponge.c

In the "Unix Programming Environment" book from 1984 there is an "overwrite" shell script depicted that does exactly this. I wonder why this never made it into the standard UNIX toolkit.
I wonder why this never made it into...

That can be said for so many of these programs.

Just to be a smartarse ;):

    cat <<EOF > output.txt
    some
    input
    EOF
Maybe I'm missing it, but this doesn't seem applicable to what my sponge program (and joeyh's) are intended to do: to modify a file "in-place".

joeyh's example:

    sed "s/root/toor/" /etc/passwd | grep -v joey | sponge /etc/passwd
My example:

    sort <foo | sponge foo
The whole point of a pipe is to have concurrent input and output. If so, and if you open the same file for input and output, you risk erasing the file by opening and deleting the file on the output side before reading it on the input side.

If the pipe is an unfulfilled promise (no concurrency) then there's no problem. But if the pipe does what it's designed to do, you will lose the file.

Maybe in my quest to be a smartarse, I'm the one missing it... but why can't you just use > in both those cases?

EDIT -- after tinkering around with the console, I see. I'm wiping the file out by writing to it (>) before it's finished reading (<). Neat, TIL!

Couldn't you just use 'tee'?

whatever <file | tee file 1>/dev/null

Oh, cool. That does seem to work, when using GNU coreutils. So either:

1. I never thought to try that. How silly of me. OR

2. Perhaps tee behaves differently on OpenBSD (which I was using at the time).

sponge () { tac|tac; }

EDIT: this doesn't work for the "sed s/foo/bar/ file|sponge file" case, but it does for certain other usages where you basically want to wait until EOF before outputting

I'm not sure I really see a point in this. How are you going to forget the server's time zone when it's listed in the timestamps? It doesn't really make sense.
It's for the cases when you are in a different timezone than the server. When the log says "03/Mar/2013 09:24:13 -0800" and it's 13:50 where I am, it takes me a while to understand how old that line is.
Right, the server says its timezone is -0800. You don't know what timezone you are currently in?
I know it's different, meaning that I have to do some basic arithmetics to get the log line age. It also requires me to roll my precious eyes to look at the local time in a system tray. It's just all too tedious.
Some services, like squid have logs with the time in UTC seconds...
I have the current time printed in my prompt, which means I can easily see how long commands took to run, eg:

    [start time] $ ./run_long_script
    [ end time ] $
My actual prompt looks like:

    [09:36] bmd-mba|bmd ~
    $ whoami
    bmd
    [09:36] bmd-mba|bmd ~
    $
Details in https://github.com/coderholic/config/blob/master/.bash_profi...
Is there a way to do this so the timestamp includes seconds? Thanks.
By default "\t" in your PS1 will display the time the same way `date +%H:%M:%S` does (which includes seconds).
Actually with that setup (which is a bit like mine) you can see how long it took from the finishing time of the last command you executed (when your PS1 was redisplayed) to the finishing of the command you just executed.
Speaking of date/time stuff, is there anything that would convert to the current time zone?

e.g. echo "03/Mar/2013 01:16:52 +0000" | mytz => 02/Mar/2013 17:16:52 -0800

$ date -d "Sun Mar 3 18:05:17 UTC 2013"

Sun Mar 3 10:05:17 PST 2013

The above converts to the system TZ. Or:

$ echo $( export TZ=CST; date -d "Sun Mar 3 18:05:17 UTC 2013" )

Sun Mar 3 18:05:17 CST 2013

The above converts from any TZ to any other TZ, without resetting your shell's TZ variable.

You can also use:

$ TZ=CST date -d "Sun Mar 3 18:05:17 UTC 2013"

Sun Mar 3 18:05:17 CST 2013

which doesn't invoke a subshell. env vars can always be prepended to the executable name for use with just that program (not sure if that's bash only, though).

For an alternative way of accomplishing the example given take a look at multitail [1]. Hitting return will insert a line with the current date and time to the file you're tailing.

It also colour codes the output and allows you to tail multiple files simultaneously.

[1] http://www.vanheusden.com/multitail/

(comment deleted)
General note: please check script before using unless you want another valentine's day ;)
That was funny seeing this here, for a minute I thought someone had posted the now.sh from my dotfiles. But I think it's no longer there. In any case mine wasn't as thoughtful, it was just a shell script to pretty print the current time, so that I could index it with Gnome-do/Kupfer/Synapse and easily call it from there. But I have since moved that responsibility to a key binding in vim, since I'm always inside the editor. All this, of course, so that I could hide the Linux Mint bar on the bottom and still see the time easily through another mean.
How about a script: a wrapper to run any other script or process, that logs both STDOUT and STDERR in one file, but prepends a short string of your choice for lines that are from STDERR.