Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

I have routinely kept my history "best effort" for many many years now by exporting HISTSIZE=10000 and HISTFILESIZE=1000000, and then occasionally doing a cp -a ~/.bash_history{,-$(date +%s)}. I actually use this history archive, and wish it was higher fidelity. (In practice, I am thinking I should just run all my sessions through script... ;P.)

http://man7.org/linux/man-pages/man1/script.1.html

I have thereby had it on my todo list for a month or so, ever since I learned of the bash DEBUG trap, to instead store my history into an sqlite3 database and have it separated by host. Seeing this reminded me "oh yeah, I really should do that" (as no: there's no way in hell I'm going to just send all of the commands I type to some random guy with a website ;P).

This is "the simplest thing that could possibly work" and might very well break if you set some crazy history configuration variables I don't use. Note that it works for pipes specifically and only because it can overwrite the same entry to the database multiple times using "insert or replace" (prevention of which is what normally makes these scripts so complex).

    histsql=~/.bash_sqlite3

    sqlite3 "${histsql}" '
        create table if not exists "session" (
            "id" integer not null primary key autoincrement,
            "address" text not null,
            "process" integer not null,
            "tty" text not null,
            "user" text not null,
            "start" timestamp not null default current_timestamp,
            "end" timestamp null
        );

        create table if not exists "command" (
            "session" integer not null,
            "line" integer not null,
            "time" timestamp not null default current_timestamp,
            "pwd" text not null,
            "text" text not null,
            primary key ("session", "line")
        );
    '

    histmac=$(ifconfig | sed -e 's/  *$//; /\(ether\|HWaddr\) / { s/.* //; q; }; d;')
    histtty=$(tty)

    histssn=$(sqlite3 "${histsql}" "
        insert into \"session\" (
            \"address\", \"process\", \"tty\", \"user\"
        ) values (
            '${histmac//\'/''}', '${$//\'/''}',
            '${histtty//\'/''}', '${USER//\'/''}'
        );

        select last_insert_rowid();
    ")

    function histend {
        sqlite3 "${histsql}" "
            update \"session\" set
                \"end\" = current_timestamp
            where
                \"id\" = '${histssn//\'/''}';
        "
    }

    trap histend EXIT

    function histadd {
        local data="$(HISTTIMEFORMAT= history 1)"
        if [[ -z $data ]]; then return; fi

        data="${data#"${data%%[![:space:]]*}"}"
        local line="${data%%' '*}"

        data="${data#*' '}"
        data="${data#"${data%%[![:space:]]*}"}"

        sqlite3 "${histsql}" "
            insert or replace into \"command\" (
                \"session\", \"line\",
                \"pwd\", \"text\"
            ) values (
                '${histssn//\'/''}', '${line//\'/''}',
                '${PWD//\'/''}', '${data//\'/''}'
            );
        "
    }

    trap histadd DEBUG


"(In practice, I am thinking I should just run all my sessions through script... ;P.)"

I've been doing this for on-call work, actually. It really helps to be able to review what was seen, what was done, how long things took, &c.

For me, the purpose of a typescript is almost entirely unrelated to the purpose of a history, though - history is things I reach for, more than things I review.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: