9

I'm new to bash and I can not for the life of me figure out how to run a certain command, suppose ./fff and print regular stdouts before stderr (I'm confused about the meaning myself)

for example

$ printf "I am a\ndrill\n" > fff; 
$ cat fff nofile fff nofile fff

I am a
drill
cat: nofile: No such file or directory
I am a
drill
cat: nofile: No such file or directory
I am a
drill

needs to print like:

I am a
drill
I am a
drill
I am a
drill
cat: nofile: No such file or directory
cat: nofile: No such file or directory

I understand that I need to redirect my output first to a file and then append the error to the same file however this is the output I get for

$ cat ./foo nofile ./foo nofile ./foo <<< $(touch fin) > see 2>> see 

I am a
drill
I am a
drill
I am a
drill
ectory
cat: nofile: No such file or directory
  • 2
    Did cat really replace "a" by "some"? – Dmitry Grigoryev Jan 15 '18 at 13:06
  • oh dang I might have messed up the string. I'll edit it right away @DmitryGrigoryev – MeOw Jan 15 '18 at 15:44
18

You'll need to hold the stderr output somewhere anyway to be able to display it at the end.

A file comes to mind:

fff 2> file; cat file >&2

Or memory (here using sponge from moreutils):

{ fff 2>&1 >&3 3>&- | sponge >&2 3>&-; } 3>&1
  • {...} 3>&1: within {...} file descriptor (fd) 3 points to the same resource as the original stdout (so we can use it to restore stdout for fff).
  • fff <redirs> | sponge <redirs>, fff and sponge started concurrently (with <redirs> applied independently) with fff's stdout going to a pipe, and sponge's stdin being the other end of the pipe.
  • 2>&1: fd 2 of fff (stderr) points to the same thing as on 1: the pipe at this point, so fff's error go to sponge via that pipe.
  • >&3: now stdout points to the original stdout (redirect back to what it was)
  • 3>&-: we close fd 2 which fff doesn't need
  • sponge accumulates its input and only displays it (on its stdout which has been redirected with >&2 to the same resource as stderr) after it has detected eof on its stdin (assumed to be when fff terminates and has already written all its output on its stdout).

If sponge is not installed, you can replace it with perl -0777 -pe ''. With -pe '', perl reads one record at a time from its input and writes it on stdout. -0777 is the slurp mode where the (only one in that case) record is the whole input.

  • Please kindly break it down if you have the time! – George Udosen Jan 14 '18 at 22:20
  • Can we use tee instead of sponge ...? – George Vasiliou Jan 14 '18 at 22:44
  • @GeorgeUdosen see edit. – Stéphane Chazelas Jan 14 '18 at 22:45
  • 1
    @GeorgeVasiliou, tee doesn't hold data, it writes it as soon as it reads it. – Stéphane Chazelas Jan 14 '18 at 22:46
  • 2
    @MeOw: That’s fine, but, as the third line of Stéphane’s answer shows, you don’t need to save the stdout; just do cat foo nofile foo nofile foo 2> ferr.txt; cat ferr.txt.  (And you probably don t want to use >>.)  Also, Stéphane makes the excellent point that you should probably do cat ferr.txt >&2 to write the stderr information to the stderr. – G-Man Says 'Reinstate Monica' Jan 15 '18 at 5:04

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.