3

I am running the latest mac OS and using zshell, and having trouble writing a shell script. I do most of my work from the command line, and wanted to have a bash script automatically save and log all of my input commands and output.

My most obvious choice was the bash "script" command, generally initiated on the command line as

script -a <filename>.txt

I wrote a shell script, log.sh, whose contents are below:

#! /bin/sh
echo "Welcome to the jungle."

# get date
now=$(date +%Y_%m_%d)

# create filename
fname='log_'$now'.txt'

# file save location
floc=~/path/to/directory/$fname

# start script
script -a -q  $floc

This starts a script where the filename is today's date and saved in a designated directory. This works fine, except, however, the contents that are written to the file. Instead of just the plan text input/outputs I would expect, I get what I believe to be ANSI characters that make the file difficult to read.

Here is what my command line looks like:

~$ bash log.sh      
Welcome to the jungle.
~$ echo "Hello world"
Hello world
~$ exit

Saving session...
...copying shared history...
...saving history...truncating history files...
...completed.

And how it is recorded in the log file:

[1m[7m%[27m[1m[0m                                                                                                  
 
]7;file://<myname>/Users/<myusername>
[0m[27m[24m[J[36m<myusername>  [38;5;246m~[39m$ [K[?2004heecho "Hello world! "[?2004l

Hello world
[1m[7m%[27m[1m[0m                                                                                                  
 
]7;file://<myname>/Users/<myusername>
[0m[27m[24m[J[36m<myusername> [38;5;246m~[39m$ [K[?2004heexit[?2004l


Saving session...
...copying shared history...
...saving history...truncating history files...
...completed.

I am aware there are a few ways to handle the ANSI keys after creating the file, such as using the cat command to display the text, or a perl script to remove the keys; However, using the cat command is annoying when I am trying to look through a large file, and having to cleanup the file manually is tedious. Is there any way I can record my command line inputs and outputs without the ANSI keys?

Thank you!

2
  • This answers your question: Convert tty terminal output to plain text Commented Apr 4, 2023 at 22:43
  • In the default macOS Terminal app, + S will save the session contents to a text file that does not appear to have the color escapes. There's reportedly a similar option in iTerm2.
    – Gairfowl
    Commented Apr 5, 2023 at 7:43

2 Answers 2

0

the easy way out is to look at the file with less -R. That is not exactly what you ask for, but might be helpful anyway.

0

This appears to work:

#!/usr/bin/env zsh
{
    # Create a named pipe, using a temp file name.
    mkfifo -m 600 ${fifo::=$(mktemp -u)}

    logFile="~/logs/log-$(date +%F-%H-%M-%S).txt"
    print "Logging to $logFile"

    # Launch the filter in the background (&), so it will
    # run in parallel with the script utility.
    # This will read from the named pipe, remove the ansi
    # color escapes, and write the result to the log.
    # (perl source: https://superuser.com/a/1388860).
    perl -pe 's/\e\[[\x30-\x3f]*[\x20-\x2f]*[\x40-\x7e]//g;
              s/\e[PX^_].*?\e\\//g;
              s/\e\][^\a]*(?:\a|\e\\)//g;
              s/\e[\[\]A-Z\\^_@]//g;' \
        < $fifo > ${~logFile} &

    # Get the process id of the background process.
    fifoPid=$!

    # Launch the script utility, capturing data from the
    # interactive shell. -F ensures writes are immediately
    # available in other processes.
    script -q -F $fifo
    # script -q -F $fifo bash

    # The background process will end when the script
    # utility closes its handle to the fifo, i.e. when the
    # shell launched by 'script' exits. But it may not exit
    # immediately, so it could be running when we get to
    # this point. This will bring it to the foreground, just
    # in case some other actions follow this script.
    wait $fifoPid

} always {
    # cleanup temp fifo.
    if [[ -p $fifo ]] rm $fifo
}

This uses a named pipe so that the output from script is filtered in real time. You could also run the cleanup filter as a post process in the shell program that launches script, but that's not nearly as interesting.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .