Potential solution
After some research and experimenting, here's what I came up with:
logstuff(){
while true; do
case $1 in
"on" ) exec > >( ( printf ">>>>> TIME:$(date) SHELLPID:$$;\n"; tee /dev/tty ; printf ">>>>>\n" ) >> logfile.txt) 2>&1 ;
break;;
"off") exec > /dev/tty 2>&1 ;
break;;
*) echo "Please type 'on' or 'off';;
esac
done
}
This bash function should be placed in your ~/.bashrc
and is available for use when opening new terminal or after issuing source ~/.bashrc
. Logging has to be turned on manually via on
and off
arguments.
DEMO
Here's how it works in practice:
Do stuff in shell 1:
<shell 1>$ logstuff on
<shell 1>$ stat /etc/passwd
File: /etc/passwd
Size: 2208 Blocks: 8 IO Block: 4096 regular file
Device: 802h/2050d Inode: 156236 Links: 1
Access: (0644/-rw-r--r--) Uid: ( 0/ root) Gid: ( 0/ root)
Access: 2018-12-01 20:24:02.620000000 +0000
Modify: 2018-10-31 01:33:42.701000999 +0000
Change: 2018-10-31 01:33:42.704998999 +0000
Birth: -
<shell 1>$ logstuff off
<shell 1>$
Do stuff in shell 2:
< shell 2 >$ logstuff on
< shell 2 >$ echo "Hello World !"
Hello World !
< shell 2 >$ logstuff off
< shell 2 >$
Now review the logfile.txt
:
<shell 1>$ cat logfile.txt
>>>>> TIME:Sat Dec 1 21:43:00 UTC 2018 SHELLPID:2225;
<shell 1>$ stat /etc/passwd
File: /etc/passwd
Size: 2208 Blocks: 8 IO Block: 4096 regular file
Device: 802h/2050d Inode: 156236 Links: 1
Access: (0644/-rw-r--r--) Uid: ( 0/ root) Gid: ( 0/ root)
Access: 2018-12-01 20:24:02.620000000 +0000
Modify: 2018-10-31 01:33:42.701000999 +0000
Change: 2018-10-31 01:33:42.704998999 +0000
Birth: -
<shell 1>$ >>>>> TIME:Sat Dec 1 21:43:11 UTC 2018 SHELLPID:2359;
< shell 2 >$ echo "Hello World !"
Hello World !
< shell 2 >$ logstuff off
>>>>>
logstuff off
>>>>>
<shell 1>$
Issues
- If
logstuff on
is issued in both terminals first, there's a chance of outputs being mangled together. The way it works is that you have to issue logsutff on
in shell 1, then issue commands there, then issue logstuff on
in shell 2.
- This uses process substitution
>( )
, tee
and a subshell. Not the most elegant nor efficient due to bunch of forking and extra pipeline.
logfile.txt
is stored in current working directory. This should be changed to ~/logfile.txt
or however the user sees fit.
Practical considerations
What the question itself asks is somewhat impractical: storing output from multiple shells into one single file means you're storing output of commands from two or more completely unrelated session, which may have different environment variables, different working directories, or working on different filesystems; this means there's whole lot of context lacking if you're intending to use such log text for debugging purposes or solving a problem.
Far better approach would be to have script -f
write to log files in one specific directory, potentially with filenames of such logs timestamped or appended the shell PID. Another solution - instead of having 3 different terminals, just use one - screen
or my personal favorite byobu-screen
. You can attach/detach to a single virtual tty session in screen and it is often used to keep processes running on remote servers where you have to log out but still need a shell session with output and tracebacks running. This can be combined with script
as well.
~/.bashrc
, which gets sourced when interactive shell is open 2)script
is as good as it gets when you want to log terminal / shell activity 3) merging multiple session records is going to be really difficult. So most reasonable solution isscreen
. What's being asked ( and if ever implemented ) would potentially be awkward and inefficient – Sergiy Kolodyazhnyy Dec 01 '18 at 18:51screen -f output.txt
as the command, and set it as the default profile for the short while you want to save this output. – muru Dec 01 '18 at 19:40Practical considerations
part. Instead of dealing with 3 unrelated terminals, I'd suggest just dealing with one and keeping all necessary relevant information in one place. – Sergiy Kolodyazhnyy Dec 01 '18 at 21:56