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.

2
  • 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. Commented May 24, 2021 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? Commented May 24, 2021 at 16:54

1 Answer 1

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


Sign up to request clarification or add additional context in comments.

1 Comment

Ah thanks for the code and the explanation!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.