The problem
Some programs ('called-command') receive as part of their parameters, another program with its own parameters ('indirect-command'). Such is the case of the commands time
, timeout
, stdbuf
, perf
, and many others.
I am trying to capture stdout and stderr of the 'called' as well as the 'indirect' commands in independent files.
Conceptually speaking, I want something like this, but of course, this doesn't work as I am typing it:
/usr/bin/time -p -- { \
timeout -k 10 7 { \
stdbuf -oL { \
./main >main_out.log 2>main_err.log; \
} \
} 2>timeout.log; \
} 2>time.log
In other words:
stderr
of the commandtime
into filetime.log
stderr
of the commandtimeout
into filetimeout.log
- let the
stdout
andstderr
of the commandstdbuf
be part oftimeout
's out/err. stdout
andstderr
of my programmain
into filemain_out.log
andmain_err.log
respectively.
What I have checked/tried
I am aware that time
has the option -o OUTPUT_FILE
, but that is a particular feature of time
, and I would like to know a generic way in which to capture outputs/errors of commands that are parameters of other commands.
I am suspecting that perhaps this cannot be generically done, because the 'called-command' actually just receives a number of strings. It is up to the 'called-command' to interpret those strings as its own options and from some point recognize the here called ('indirect-command'). Therefore, it is not forced to treat the characters
<
or>
in any special manner...
- In general my internet searches land to examples related to pipes,
&&
,||
, or blocks such aswhile
loops. After trying to adapt what they present, I don't think they apply here. - Surrounding the "child-arguments" in quotations marks (of different flavors,) fails because the "parent-command" tries to lookup the whole string as a command name. (Along the lines of
'timeout -k 10 7...' does not exist
) - I tried parenthesis and curly brackets as suggested here How to redirect the output of the time command to a file in Linux?, but after fidgeting for a good while, I still cannot make it work.
tee
was mentioned in the comments, but I cannot see how to use it in this case. Also, I would prefer not to pollute the results oftime
by adding new forks.
Thanks in advance.
CodePudding user response:
I think what you are trying to do can be done with tee
and exec
working together. Try the following example:
/usr/bin/time -p -- { \
exec 2>timeout.log; \
timeout -k 10 7 { \
exec > >(tee -a timeout.log) 2> >(tee -a timeout.log >&2); \
stdbuf -oL { \
exec >main_out.log 2>main_err.log; \
./main; \
} \
} \
} 2>time.log
CodePudding user response:
I wonder if this can meet your requirements :
/usr/bin/time -p --\
bash -c '"$@" 2>timeout.log' _ timeout -k 10 7 \
bash -c '"$@"' _ stdbuf -oL\
bash -c '"$@" >main_out.log 2>main_err.log' _ ./main \
2>time.log
Yes, the idea is to spawn one bash instance per "nesting-level".
I have updated main
to ./main
, it should work now.
The underscore is a placeholder for $0 of each bash process.