How do I redirect stderr
(or stdout
+stderr
) to a file if I don't know which shell (bash
, csh
, dash
) is interpreting my command?
My C code running on Linux/FreeBSD/OSX needs to call an external program via the system()
function, which will use /bin/sh
to interpret the supplied command line. I would like to capture the messages printed by that external program to stderr
and save them to a file. The problem is that on different systems /bin/sh
points to different shells that have different syntax for redirecting the stderr
stream to a file.
The closest thing I found is that bash actually understands the csh
-style syntax for redirecting stderr
+stdout
to a file:
some_program >& output.txt
but dash
, which is the default shell on Ubuntu (i.e. very common), does not understand this syntax.
Is there a syntax for stderr
redirection that would be correctly interpreted by all common shells? Alternatively, is there a way to tell system()
(or some other similar C function?) to use /usr/bin/env bash
instead of /bin/sh
to interpret the supplied command line?
You have a mistaken assumption, that /bin/sh
can be an "alternate" shell like csh
that's incompatible with the standard shell syntax. If you had a system setup like that, it would be unusably broken; no shell scripts would work. Pretty much all modern systems attempt to conform, at least superficially, to the POSIX standard, where the sh
command processes the Shell Command Language specified in POSIX, which is roughly equivalent to the historical Bourne shell and which bash
, dash
, ash
, etc. (shells which are commonly installed as /bin/sh
) are all 99.9% compatible with.
You can completely ignore csh
and similar. They're never installed as sh
, and only folks who actually want to use them, or who get stuck using them as their interactive shell because some evil sysadmin setup the login shell defaults that way, ever have to care about them.
How do I redirect stderr (or stdout+stderr) to a file if I don't know which shell (bash, csh, dash) is interpreting my command?
You don't. Bourne-family shells and csh-family shells have different, incompatible syntax for redirecting stderr. In fact, csh
and tcsh
do not have a syntax to redirect only stderr at all -- they can redirect it only together with stdout.
If you really could be in any shell at all, then you're pretty much hosed with respect to doing much of anything. One could imagine an obscure, esoteric shell with completely incompatible syntax. For that matter, even an unusual configuration of a standard shell could trip you up -- for example if the IFS
variable is set to an unusual value in a Bourne-family shell, then you'll have trouble executing any commands that don't take that into account.
If you can count on executing at least simple commands, then you could execute a known shell within the unknown one to process your command, but that oughtn't to be necessary for the case that seems to interest you.
Alternatively, is there a way to tell system() (or some other similar C function?) to use /usr/bin/env bash instead of /bin/sh to interpret the supplied command line?
Not on a POSIX-conforming system. POSIX specifies explicitly that the system()
function executes the command by use of /bin/sh -c [the_command]
. But this shouldn't be something to worry about, as /bin/sh
should be a conforming POSIX shell, or at least pretty close to one. Definitely it should be a Bourne-family shell, which both bash
and dash
are, but tcsh
most definitely is not.
The way to redirect the standard error stream in a POSIX shell is to use the 2>
redirection operator (which is a special case of a more general redirection feature applicable to any file descriptor). Whatever shell /bin/sh
actually is should recognize that syntax, and in particular bash
and dash
both do:
some_program 2> output.txt
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With