14

I'm watching the output of my complicated command with less, problem is the stderr gets lost. stderr lines normally get listed inbetween stdout lines inside less. I would like them to be printed to the console, and when I exit less, to see them there together.

I realize there might be no solution to this, I read about tee and multitee but no luck so far.

Duijf
  • 689
  • 4
  • 17
haelix
  • 348
  • 3
  • 15
  • 2
    You're telling me how to redirect stderr to stdout but that's not what I wanted. I don't want stderr to mix with stdout inside less. I would like stderr to be in the terminal when I exit less. –  Dec 10 '11 at 14:17
  • If `stderr` is redirected to `stdout`, all output to `stderr` _will_ be mixed with the normal output on `stdout`. Piping that output to `less` will show both. – Some programmer dude Dec 10 '11 at 15:15
  • If I ignore "stderr to be in the terminal when I exit less", I suggest to press Ctrl-L in `less` to repaint the screen. – kamae Dec 13 '11 at 13:40

7 Answers7

24

You have to redirect stderr to stdout:

$ ./somecommad 2>&1 | less

Check the manual for you shell (e.g. man bash.)

  • 2
    Comment for new readers of this old question (not for Joachim particularly) This is what everyone thinks at first scan of the question. But the problem is more subtle - see discussion in comments after [dmckee's answer](http://superuser.com/a/366615/52492) – RedGrittyBrick Jun 20 '16 at 09:19
  • 2
    The shorthand for **2>&1** is **|&**. Thus, it can be simplified as `$ ./somecommad |& less` – Melvin Abraham May 18 '20 at 14:51
  • 1
    In Fish, it's the other way around: `./somecommad &| less` – Julia Mar 01 '21 at 20:12
11

Maybe

command 2> command.err | less; cat command.err; rm command.err

Addendum

Here follows a clarification for folk who neglect to carefully read the question and who didn't read the OP's clarifying comment above.

haelix pointed out:

stderr lines normally get listed inbetween stdout lines inside less

and, in a comment for early answerers, wrote:

You're telling me how to redirect stderr to stdout but that's not what I wanted. I don't want stderr to mix with stdout inside less. I would like stderr to be in the terminal when I exit less

The problem is probably platform specific, it is certainly something I have experienced on older Unix SVR4 platforms.

If, on such platforms, you do something like

 find / ... | less

any error messages (e.g. directory permissions) appear like this in less

 stdout line 1
 stdout line 2
 error message text
 stdout line 4

so that output lines are obscured by error messages.

If you refresh the page the output lines are shown correctly but you lose the error messages. When you exit less the screen is cleared except for a command prompt.

If you do something like

  find / ... 2>&1 | less

The error messages are intermingled with the standard output. Again when you exit less, the screen is empty.

If you want to first peruse only the standard output in less, then see the error messages after exiting less, you need a different solution.

That is what I was tentatively suggesting in my original, two-line answer.

RedGrittyBrick
  • 81,981
  • 20
  • 135
  • 205
  • This is garbage. Joachim's answer should be the one accepted. – Vanilla Face Jun 20 '16 at 06:38
  • 3
    @VanillaFace: I have added some clarifying material to my answer. – RedGrittyBrick Jun 20 '16 at 09:09
  • @VanillaFace: No, RedGrittyBrick answers exactly to the question asked, as opposite to most other answers which address a different question. His answer was useful at least to me (I found it when I experienced exactly the same problem as OP and wanted stderr to persist after exiting less, which was not the case in Ubuntu by default). – fiktor Dec 25 '20 at 21:08
2

just tell the shell to redirect fd 2 to fd 1 (stderr to stdout)

 make 2>&1 | less
jackdoe
  • 129
  • 2
1

One thing that was lacking from all the answers so far is the reason, why this is happening. The problem here is some kind of race-condition between the process outputting stuff to stderr and less displaying output from stdout on the terminal. If less starts displaying after all output to stderr has been printed to the terminal, then less will preserve that and you can see the messages after exiting less. OTOH if less has already started displaying stuff, then error messages intermingle with less's output and nothing is preserved after less exits (because less just preserves the terminal as it was before it started and doesn't know anything about the error messages that came in between).

You can see that easily, if you do e.g.

grep foo -r /etc | less

All the "Permission denied" error messages mix up with less output and nothing will be there after you exit. If you do

grep foo -r /etc | (sleep 10; less)

all (or at least most) of the error messages have been printed to the terminal before less gets a chance to display output and you will see the error messages afterwards.

Of course, you don't usually want to wait 10 seconds before you start less, but with Linux you can also supply fractional values for the waiting time, and with fast running processes often something as little as sleep 0.1 is enough to avoid the race condition. (But, of course, if you want or have to be on the really safe side use RedGrittyBrick's solution).

Elmar Zander
  • 111
  • 2
0

You need to understand the concept of "file descriptors". Usually, a unix application will start with three special file descriptors:

  • Standard input
  • Standard output
  • Standard error

The "pipe" | in the shell connects stdout from one process with stdin of the next.

Errors are - by design - not fed to stdin of the next process. They will often not make sense to the next application, and should not be hidden from the user.

If you want to mix the errors into stdout, you can use e.g. 2>&1, which says essentially "append stderr to stdout". For example

find /etc 2>&1 | less

should also include error output from inaccessible files.

find /etc 2>&1 >/dev/null | less

will give you the errors only.

0

I'm confused about your question, as far as I ca tell your desired behavior is the default.

When I use

#include <stdio.h>

int main(int argc, char**argv){
  for (int j=0; j<10; ++j){
    fprintf( (j%2 ? stdout : stderr) , "%d\n" , j);
  }
  return 0;
}

to get a simple test,

$ ./testredirection | less

does just what you ask. That is I see

1
3
5
7
9
(END) 

in less and

$ ./testredirection | less
0
2
4
6
8
$ 

when I quit less

  • It's strange but things are not always like this. Try with a script (`echo info ; echo error 1>&2`) and repeat the test: both lines are piped to less. – cYrus Dec 10 '11 at 16:19
  • @cYrus: That works as expected for me, too. 'Course I tried in on a Mac OS box. Bash 3.2.17, less 394. Maybe something linux specific. In any case RedGrittyBrick's approach should work fine. – dmckee --- ex-moderator kitten Dec 10 '11 at 16:26
  • Weird! Debian Squeeze / Bash 4.1.5 / Less 436 – cYrus Dec 10 '11 at 16:32
  • Yeah, I opened a shell of Scientific Linux 5.3 box at work and got the expected behavior with bash 3.0.15 and less 382. Could there be a regression in there? – dmckee --- ex-moderator kitten Dec 10 '11 at 16:39
  • I don't know, I think it's just a matter of buffering. – cYrus Dec 10 '11 at 16:54
  • @cYrus: It occurs to me that the difference is probably the *terminal* we're using, as both my tests were in `xterm`s (version 269) from the XQuartz 2.6.3. Indeed, the Mac OS 10.5 `Terminal.app` gets it "wrong" the first time then "right" subsequently. Huh? I guess that argues in favor of a buffering explanation, but I'm not going to try to figure it out any more. – dmckee --- ex-moderator kitten Dec 10 '11 at 17:25
  • 1
    The default behavior I'm getting (with no redirection) is that stderr lines get outputted in less but in an ephemeral way: if you scroll them out of view and go back, they're not there (neither are they in the console after less exits). – haelix Dec 10 '11 at 20:47
  • On Ubuntu 20.04.1 LTS and on Ubuntu 18.04.4 LTS with GNU bash versions 5.0.17 and 4.4.20 respectively, Konsole terminal, I get similar behavior to OP and @haelix: - When the output is less than 1 screen long, `stderr` is intermingled with stdout in `less` output, and lost after closing `less` or redrawing (`CTRL+L`). - When the output is more than 1 screen long, intermingling is a bit out of order, has erroneous `:` symbol in the middle of the screen (which is supposed to be at the bottom to indicate the `less` prompt); `stderr` is lost on scrolling, redrawing, or exiting `less`. – fiktor Dec 25 '20 at 21:39
0

I happen to encounter this problem in one of my Debian 5.0's recently. for example, ls abc | less I find that the error message go into less, which against my knowledge.

After some attempts, I found that it is just something related to screen buffers. stderr does NOT go into less actually. You can use Up or Down arrow keys (or j/k) to demonstrate.

Berry
  • 471
  • 1
  • 5
  • 5