I have a script that do many action, and echo information. I want to have a "duplicate" of all what is printed to the terminal into a file, and I want to add some information into it as well.
Problem : i can't simply piping every echo into tee
because some printing are done by function that are sourced from another source file, and I can't modify them.
So I searched and I found this redirect COPY of stdout to log file from within bash script itself
So based on that, i do the following script
#!/bin/bash
strReportingFilepath="./reporting.log"
echo "[1] stdout : This text will not appear in the reporting file"
echo "[2] stderr : Neither this one" >&2
# We dup stdour and stderr into the reporting file (reporting fiel emptied)
exec > >(tee -i "$strReportingFilepath") 2>&1
echo "[3] stdout : This text will be on both the terminal and the reporting file"
echo "[4] stderr : This one too :)" >&2
echo "[5] stdout : Last case : this text should only appear into the reporting file" >> "$strReportingFilepath"
exit 0
When I run this script, I have this on my terminal
(terminal info) # ./my_script.sh
[1] stdout : This text will not appear in the reporting file
[2] stderr : Neither this one
(terminal info) # [3] stdout : This text will be on both the terminal and the reporting file
[4] stderr : This one too :)
and this into my file
(terminal info) # cat reporting.log
[3] stdout : This text will be on both the terminal and the reporting file
[4] stderr : This one too :)
I have 2 problem :
First, for an unknow reason (I suspect that I use exec/named pipe/tee in a sloppy way), my script actually wait at the end. I have to press enter key in order to terminate the script.
Secondly, the [5] echo doesn't appear into the file.
I'm pretty sure that I mess something up with the exec line, but I can't understand what and I don't know what to do.
I added a "sync" call after the [5] echo, but it didn't work.
Well, I think I finally managed to do what I wanted.
What I want :
- Having everything printed onto the screen terminal (stdout, stderr, stdin) to be "logged" into a file
- Having the possibility to add text into this logging file without displaying it onto the terminal screen.
I stopped using tee, and I found a link talking about "script(8)". After tinkering around, I ended up with this script :
#!/bin/bash
strReportingFilepath="./reporting.log"
# Part that will do the script reporting
if [ -z "$SCRIPT" ]; then
export SCRIPT="$0"
# Creation of the string bash command
strCommand="$0"
strSearch="'"
strReplace="'\''"
for strArgument in "$@"; do
strCommand+=" '${strArgument//$strSearch/$strReplace}'"
done
# Execution of the script
/usr/bin/script --return --quiet --flush --append "$strReportingFilepath" --command "$strCommand"
# We get the return
intScriptReturnValue="$?"
# The line automaticly added by /usr/bin/script is something that I don't want
strTemporaryFilepath="$(mktemp)"
grep -v '^Script started on ' "$strReportingFilepath" > "$strTemporaryFilepath"
mv "$strTemporaryFilepath" "$strReportingFilepath"
exit "$intScriptReturnValue"
fi
# "Start" of the script that I want "supervised"
sync
echo "[0 ] directly" >> "$strReportingFilepath"
echo "[1. ] out"
sync
echo "[1.5] directly" >> "$strReportingFilepath"
echo "[2 ] out"
echo "[3. ] err" >&2
sync
echo "[3.5] directly" >> "$strReportingFilepath"
echo "[4 ] err" >&2
echo -n "[5 ] input : "
read
echo "[6 ] out"
echo "[7 ] err" >&2
echo " End :)"
exit 5
Now, there are still some problem :
I really don't know what I have done, so if you're thinking about using this code as it, think about it twice. I just know that for my case, it "seem to work" (yeepee !)
Each time I want to write something directly into the logging file, I have to call "sync" before. Without it, the line aren't in order. Please note that "sync" doesn't garanty that it's instantaneous. In the doc, they say that command like "halt" do a "sleep" after a sync in order to be sure, so it's still possible to have race condition resulting in wrong line order.
It seem that "script" doesn't work on some case, like when stdin is not a terminal. See "script(8)".
Well, sorry for this strange question, I would have bet that what I wanted to do was simple and common, turn out not really.