0

I'm trying to save my entered commands and their respective outputs in a file.
What I'm currently doing:

mylog() {
    echo "----------------" >> ${PWD}/cmds.log
    echo "$@" >> ${PWD}/cmds.log
    # read foo # Tried reading the piped value in to
    # echo "$foo" >> ${PWD}/cmds.log
    # MYCMD="${@}"
    # echo "$MYCMD" >> ${PWD}/cmds.log
    "$@" | tee -a ${PWD}/cmds.log
}

It currently functions like: mylog cat file.txt | mylog sort
And the output in cmds.log is:

----------------
cat file.txt
----------------
sort
....
output from cat
...
output from sort
...

What I'd like is:

----------------
cat file.txt
....
output from cat
...
----------------
sort
...
output from sort
...

In the code, you can see I tried using read and following other method described here.
I also tried doing VAR=${@} but this just saved the command twice and doesn't execute it.

Any idea of how I can accomplish my goal?

Slightly related, I'm manually saving the terminals output like this, and not using script because the interactive shell causes lots of escape characters and such to be caught.

Will
  • 1,059
  • 2
  • 10
  • 22
  • If you want to strip the interactive prompt, will setting `PS1` to `''` work? BTW, the output is like that because all fragments in a pipe are run in parallel, rather than sequential. – dibery May 24 '21 at 16:46
  • @dibery The type completition of my shell causes each variation that is suggested to be outputted, so PS1='' doesn't help. How could I run them sequentially? – Will May 24 '21 at 16:54

1 Answers1

1

Your modified script...

#!/usr/bin/env bash

mylog() {
    local output="log"
    
    # This is the key part right here. The 'tac' command here
    # prints stdin in reverse. To do this, it must read _all_
    # of stdin, so it buffers until it reads everything. Of course,
    # we must use two 'tac's so stdin doesn't actually get reversed.
    # You could also use `sponge(1)` here, but that does not come standard
    # on all Linux distributions / MacOS
    local buffer="$("$@" | tac | tac)"

    # Nothing below will be printed until 'buffer' is completely filled with stdin
    {
        echo "----------------"
        echo "$@"
        echo "----------------"
        echo "$buffer"
        echo
    } >> "$output"

    printf "%s" "$buffer" 
}

rm -f log
mylog cat file.txt | mylog sort >/dev/null

The resulting log

----------------
cat file.txt
----------------
bravo
alfa
charlie
delta
echo

----------------
sort
----------------
alfa
bravo
charlie
delta
echo


hyperupcall
  • 869
  • 10
  • 21