Restore specific Terminal history from .bash_sessions

high sierraterminal

My Terminal windows restored correctly after updating to High Sierra–but each only has a single tab in it; none of the other tabs restored.

I've got all of the history files from ~/.bash_sessions, so I think the worst-case is that I am only able to recover the command history by manually opening new tabs and replacing the histories.

Does anyone know of a way to recover the scrollback history, given these session IDs (or perhaps the window GUIDs, from com.apple.Terminal.savedState/windows.plist)?

Best Answer

After some googling, I found this script on pastebin from an anonymous user. I haven't had a chance to try it myself, but it looks like it has potential with some modifications.

# Separate Command Histories for Restored Terminal Sessions

# Terminal assigns each terminal session a unique identifier and
# communicates it via the TERM_SESSION_ID environment variable so that
# programs running in a terminal can save/restore application-specific
# state when quitting and restarting Terminal with Resume enabled.

# The following script saves and restores the bash command history
# independently for each restored terminal session. It also merges
# commands into the global history for new sessions. Because of this
# it is recommended that you set HISTSIZE and HISTFILESIZE to larger
# values (their default value is 500). Old sessions are periodically
# deleted.

if [ -z "$BASH_SESSION" ] && [ -n "$TERM_SESSION_ID" ]; then

    # Only perform this setup once per shell session (which shouldn't
    # happen unless the user's ~/.bash_profile executes /etc/profile,
    # which is normally redundant).
    BASH_SESSION=1

    # Set up the session directory/file.
    if [ -z "$BASH_SESSION_DIR" ]; then
        BASH_SESSION_DIR="$HOME/.bash_sessions"
        BASH_SESSION_FILE="$BASH_SESSION_DIR/$TERM_SESSION_ID.session"
    elif [ -z "$BASH_SESSION_FILE" ]; then
        BASH_SESSION_FILE="$BASH_SESSION_DIR/$TERM_SESSION_ID.session"
    fi
    mkdir -p "$BASH_SESSION_DIR"

    # Arrange for session-specific shell command history. Users can
    # disable this via the existence of the following file.
    [ -f ~/.bash_session_no_history ] && BASH_SESSION_HISTORY=0 || BASH_SESSION_HISTORY=1
    if [ $BASH_SESSION_HISTORY -eq 1 ]; then
        BASH_SHARED_HISTFILE="$HISTFILE"
        BASH_SESSION_HISTFILE="$BASH_SESSION_DIR/$TERM_SESSION_ID.history"
        BASH_SESSION_HISTFILE_NEW="$BASH_SESSION_DIR/$TERM_SESSION_ID.historynew"
        # If the session history doesn't exist, copy the shared history
        if [ -f "$BASH_SHARED_HISTFILE" ] && [ ! -f "$BASH_SESSION_HISTFILE" ]; then
            cp "$BASH_SHARED_HISTFILE" "$BASH_SESSION_HISTFILE"
        else
            # Ensure the file exists and doesn't get expired.
            touch "$BASH_SESSION_HISTFILE"
        fi
        history -r "$BASH_SESSION_HISTFILE"
        : >| "$BASH_SESSION_HISTFILE_NEW"
        HISTFILE="$BASH_SESSION_HISTFILE_NEW"
    fi

    if [ "$SHLVL" -eq 1 ]; then
        # Restore previous session state.
        if [ -f "$BASH_SESSION_FILE" ]; then
            . "$BASH_SESSION_FILE"
            rm "$BASH_SESSION_FILE"
        fi

        # Save the current state.
        bash_save_session_state() {
            if [ "$SHLVL" -eq 1 ] && [ -n "$BASH_SESSION_FILE" ]; then
                echo -n Saving session...
                echo echo Restored session: $(date) > "$BASH_SESSION_FILE"

                # Users can add custom state by defining the following
                # function. e.g., to save an environment variable:
                #   bash_session_save_state() { echo MY_VAR="'$MY_VAR'" >> "$BASH_SESSION_FILE"; }
                declare -F bash_session_save_state >/dev/null && bash_session_save_state

                # Save new history commands.
                if [ $BASH_SESSION_HISTORY -eq 1 ]; then
                    history -a
                    cat "$BASH_SESSION_HISTFILE_NEW" >> "$BASH_SHARED_HISTFILE"
                    cat "$BASH_SESSION_HISTFILE_NEW" >> "$BASH_SESSION_HISTFILE"
                    # Empty this session's history file to keep track of
                    # which commands have already been copied.
                    : >| "$BASH_SESSION_HISTFILE_NEW"
                    # Read/write the files via the history command so they
                    # are truncated as appropriate.
                    history -r "$BASH_SHARED_HISTFILE"
                    history -w "$BASH_SHARED_HISTFILE"
                    history -r "$BASH_SESSION_HISTFILE"
                    history -w "$BASH_SESSION_HISTFILE"
                fi

                echo completed.
            fi
        }

        # Delete old session files. Do not do this more frequently
        # than once a day.
        BASH_SESSION_TIMESTAMP_FILE="$BASH_SESSION_DIR/_expiration_check_timestamp"
        bash_delete_expired_session_state() {
            if ([ ! -f "$BASH_SESSION_TIMESTAMP_FILE" ] || [ -z $(find "$BASH_SESSION_TIMESTAMP_FILE" -mtime -1d) ]); then
                local bash_session_lock_file="$BASH_SESSION_DIR/_expiration_lockfile"
                if shlock -f "$bash_session_lock_file" -p $$; then
                    echo -n Deleting expired sessions...
                    local delete_count=$(find "$BASH_SESSION_DIR" -type f -mtime +2w -print -delete | wc -l)
                    [ "$delete_count" -gt 0 ] && echo $delete_count completed. || echo none found.
                    touch "$BASH_SESSION_TIMESTAMP_FILE"
                    rm "$bash_session_lock_file"
                fi
            fi
        }

        # Update saved session state when exiting.
        bash_update_session_state() {
            bash_save_session_state && bash_delete_expired_session_state
        }
        trap bash_update_session_state EXIT
    fi
fi