Сохранение текущего каталога в историю bash


Я хотел бы сохранить текущий каталог, где каждая команда была выпущена вместе с командой в истории. Чтобы не испортить ситуацию, я думал о добавлении текущего каталога в качестве комментария в конце строки. Пример может помочь:

$ cd /usr/local/wherever
$ grep timmy accounts.txt

Я бы хотел, чтобы bash сохранил последнюю команду как:

grep timmy accounts.txt # /usr/local/wherever

идея в том, что таким образом я мог сразу увидеть, где я выдал команду.

7   51   2009-06-03 19:01:17

7 ответов:

однострочная версия

вот однострочная версия. Это оригинал. Я также опубликовал короткую версию функции и длинную версию функции с несколькими добавленными функциями. Мне нравятся версии функций, потому что они не будут сбивать другие переменные в вашей среде, и они гораздо более читаемы, чем однострочные. В этом посте есть некоторая информация о том, как они все работают, которые не могут быть дублированы в других.

добавить следующий код ~/.bashrc файл:

export PROMPT_COMMAND='hpwd=$(history 1); hpwd="${hpwd# *[0-9]*  }"; if [[ ${hpwd%% *} == "cd" ]]; then cwd=$OLDPWD; else cwd=$PWD; fi; hpwd="${hpwd% ### *} ### $cwd"; history -s "$hpwd"'

это делает запись истории, которая выглядит так:

rm subdir/file ### /some/dir

я использую ### в качестве разделителя комментариев, чтобы отделить его от комментариев, которые пользователь может ввести, и уменьшить вероятность коллизий при удалении старых комментариев пути, которые в противном случае накапливались бы, если вы нажмете enter в пустой командной строке. К сожалению, побочный эффект заключается в том, что команда, как echo " ### " искажается, хотя это должно быть довольно редко.

некоторые люди будут найдите тот факт, что я повторно использую одно и то же имя переменной, чтобы быть неприятным. Обычно я бы не стал, но здесь я пытаюсь уменьшить. Это легко изменить в любом случае.

он слепо предполагает, что вы не используете HISTTIMEFORMAT или изменение истории каким-то другим способом. Было бы легко добавить date команда на комментарий Вместо HISTTIMEFORMAT характеристика. Однако, если вам нужно использовать его по какой-то причине, он все еще работает в подоболочку, так как он получает сбросить автоматически:

$ htf="%Y-%m-%d %R "    # save it for re-use
$ (HISTTIMEFORMAT=$htf; history 20)|grep 11:25

есть несколько очень маленьких проблем с ним. Один из них, если вы используете history команда такая, например:

$ history 3
echo "hello world" ### /home/dennis
ls -l /tmp/file ### /home/dennis
history 3

результат не покажет комментарий к history команда сама, даже если вы увидите его, если вы нажмете стрелку вверх или выдадите другой .

другой заключается в том, что команды со встроенными новыми строками оставляют незафиксированную копию в истории в дополнение к прокомментированной копировать.

там могут быть и другие проблемы, которые появляются. Дай мне знать, если найдешь что-нибудь.

как это работает

Bash выполняет команду, содержащуюся в PROMPT_COMMAND переменная каждый раз PS1 выдается основная подсказка. Этот маленький скрипт использует это, чтобы захватить последнюю команду в истории, добавить комментарий к ней и сохранить ее обратно.

здесь он разделен на части с комментариями:

hpwd=$(history 1)              # grab the most recent command
hpwd="${hpwd# *[0-9]*  }"      # strip off the history line number
if [[ ${hpwd%% *} == "cd" ]]   # if it's a cd command, we want the old directory
then                           #   so the comment matches other commands "where *were* you when this was done?"
    cwd=$OLDPWD
else
    cwd=$PWD
fi
hpwd="${hpwd% ### *} ### $cwd" # strip off the old ### comment if there was one so they 
                               #   don't accumulate, then build the comment
history -s "$hpwd"             # replace the most recent command with itself plus the comment

hcmnt-длинная версия функции

вот длинная версия в виде функции. Это же монстр, но он добавляет несколько полезных функций. Я также опубликовал один лайнер (оригинал) и более короткую функцию. Мне нравятся версии функций, потому что они не будут сбивать другие переменные в вашей среде и они гораздо более читабельны, чем однострочные. Прочитайте запись для однострочного и commments в функции ниже для получения дополнительной информации о как это работает и некоторые ограничения. Я разместил каждую версию в своем собственном ответе, чтобы держать вещи более организованными.

чтобы использовать этот, сохраните его в файле под названием hcmnt в месте, как /usr/local/bin (можно chmod +x это если вы хотите), то источник ее в своем ~/.bashrc такой:

source /usr/local/bin/hcmnt
export hcmntextra='date "+%Y%m%d %R"'
export PROMPT_COMMAND='hcmnt'

не редактируйте файл функции, где PROMPT_COMMAND или hcmntextra задаются. Оставьте их как есть, чтобы они оставались по умолчанию. Включите их в свой .bashrc как показано выше, и редактировать их там чтобы установить параметры для hcmnt или изменить или отменить hcmntextra. В отличие от короткой функции, с этим вы оба должны иметь hcmntextra переменная и использовать -e возможность сделать эту функцию работы.

вы можете добавить несколько параметров, которые задокументированы (с несколькими примерами) в комментариях в функции. Одна примечательная особенность состоит в том, чтобы запись истории с добавленным комментарием регистрировалась в файле и оставляла фактическую историю нетронутой. Для того, чтобы использовать это функция, как раз добавьте -lfilename вот так:

export PROMPT_COMMAND="hcmnt -l ~/histlog"

вы можете использовать любую комбинацию опций, кроме этой -n и -t являются взаимоисключающими.

#!/bin/bash
hcmnt() {

# adds comments to bash history entries (or logs them)

# by Dennis Williamson - 2009-06-05 - updated 2009-06-19
# http://stackoverflow.com/questions/945288/saving-current-directory-to-bash-history
# (thanks to Lajos Nagy for the idea)

# the comments can include the directory
# that was current when the command was issued
# plus optionally, the date or other information

# set the bash variable PROMPT_COMMAND to the name
# of this function and include these options:

    # -e - add the output of an extra command contained in the hcmntextra variable
    # -i - add ip address of terminal that you are logged in *from*
    #      if you're using screen, the screen number is shown
    #      if you're directly logged in, the tty number or X display number is shown
    # -l - log the entry rather than replacing it in the history
    # -n - don't add the directory
    # -t - add the from and to directories for cd commands
    # -y - add the terminal device (tty)
    # text or a variable

# Example result for PROMPT_COMMAND='hcmnt -et $LOGNAME'
#     when hcmntextra='date "+%Y%m%d %R"'
# cd /usr/bin ### mike 20090605 14:34 /home/mike -> /usr/bin

# Example for PROMPT_COMMAND='hcmnt'
# cd /usr/bin ### /home/mike

# Example for detailed logging:
#     when hcmntextra='date "+%Y%m%d %R"'
#     and PROMPT_COMMAND='hcmnt -eityl ~/.hcmnt.log $LOGNAME@$HOSTNAME'
#     $ tail -1 ~/.hcmnt.log
#     cd /var/log ### dave@hammerhead /dev/pts/3 192.168.1.1 20090617 16:12 /etc -> /var/log


# INSTALLATION: source this file in your .bashrc

    # will not work if HISTTIMEFORMAT is used - use hcmntextra instead
    export HISTTIMEFORMAT=

    # HISTTIMEFORMAT still works in a subshell, however, since it gets unset automatically:

    #   $ htf="%Y-%m-%d %R "    # save it for re-use
    #   $ (HISTTIMEFORMAT=$htf; history 20)|grep 11:25

    local script=$FUNCNAME

    local hcmnt=
    local cwd=
    local extra=
    local text=
    local logfile=

    local options=":eil:nty"
    local option=
    OPTIND=1
    local usage="Usage: $script [-e] [-i] [-l logfile] [-n|-t] [-y] [text]"

    local newline=$'\n' # used in workaround for bash history newline bug
    local histline=     # used in workaround for bash history newline bug

    local ExtraOpt=
    local LogOpt=
    local NoneOpt=
    local ToOpt=
    local tty=
    local ip=

    # *** process options to set flags ***

    while getopts $options option
    do
        case $option in
            e ) ExtraOpt=1;;        # include hcmntextra
            i ) ip="$(who --ips -m)" # include the terminal's ip address
                ip=($ip)
                ip="${ip[4]}"
                if [[ -z $ip ]]
                then
                    ip=$(tty)
                fi;;
            l ) LogOpt=1            # log the entry
                logfile=$OPTARG;;
            n ) if [[ $ToOpt ]]
                then
                    echo "$script: can't include both -n and -t."
                    echo $usage
                    return 1
                else
                    NoneOpt=1       # don't include path
                fi;;
            t ) if [[ $NoneOpt ]]
                then
                    echo "$script: can't include both -n and -t."
                    echo $usage
                    return 1
                else
                    ToOpt=1         # cd shows "from -> to"
                fi;;
            y ) tty=$(tty);;
            : ) echo "$script: missing filename: -$OPTARG."
                echo $usage
                return 1;;
            * ) echo "$script: invalid option: -$OPTARG."
                echo $usage
                return 1;;
        esac
    done

    text=($@)                       # arguments after the options are saved to add to the comment
    text="${text[*]:$OPTIND - 1:${#text[*]}}"

    # *** process the history entry ***

    hcmnt=$(history 1)              # grab the most recent command

    # save history line number for workaround for bash history newline bug
    histline="${hcmnt%  *}"

    hcmnt="${hcmnt# *[0-9]*  }"     # strip off the history line number

    if [[ -z $NoneOpt ]]            # are we adding the directory?
    then
        if [[ ${hcmnt%% *} == "cd" ]]    # if it's a cd command, we want the old directory
        then                             #   so the comment matches other commands "where *were* you when this was done?"
            if [[ $ToOpt ]]
            then
                cwd="$OLDPWD -> $PWD"    # show "from -> to" for cd
            else
                cwd=$OLDPWD              # just show "from"
            fi
        else
            cwd=$PWD                     # it's not a cd, so just show where we are
        fi
    fi

    if [[ $ExtraOpt && $hcmntextra ]]    # do we want a little something extra?
    then
        extra=$(eval "$hcmntextra")
    fi

    # strip off the old ### comment if there was one so they don't accumulate
    # then build the string (if text or extra aren't empty, add them plus a space)
    hcmnt="${hcmnt% ### *} ### ${text:+$text }${tty:+$tty }${ip:+$ip }${extra:+$extra }$cwd"

    if [[ $LogOpt ]]
    then
        # save the entry in a logfile
        echo "$hcmnt" >> $logfile || echo "$script: file error." ; return 1
    else

        # workaround for bash history newline bug
        if [[ $hcmnt != ${hcmnt/$newline/} ]] # if there a newline in the command
        then
            history -d $histline # then delete the current command so it's not duplicated
        fi

        # replace the history entry
        history -s "$hcmnt"
    fi

} # END FUNCTION hcmnt

# set a default (must use -e option to include it)
export hcmntextra='date "+%Y%m%d %R"'      # you must be really careful to get the quoting right

# start using it
export PROMPT_COMMAND='hcmnt'

обновление 2009-06-19: добавлены опции, полезные для ведения журнала (ip и tty), обходной путь для Проблемы с дублированием записи, удалены посторонние нулевые назначения

вы можете установить Расширенная История Оболочки, инструмент с открытым исходным кодом, который пишет ваш bash или zsh история в базу данных sqlite. Это записывает такие вещи, как текущий рабочий каталог, код выхода команды, время запуска и остановки команды, время запуска и остановки сеанса, tty и т. д.

если вы хотите запросить базу данных истории, вы можете написать свои собственные SQL-запросы, сохранить их и сделать их доступными в комплекте . Есть несколько полезных предварительно упакованные запросы, но так как я знаю SQL довольно хорошо, я обычно просто открываю базу данных и запрашиваю интерактивно, когда мне нужно что-то искать.

один запрос, я нахожу очень полезным, хотя, глядя на историю текущего рабочего каталога. Это помогает мне вспомнить, где я остановился, когда работал над чем-то.

vagrant@precise32:~$ ash_query -q CWD
session
    when                   what
1
    2014-08-27 17:13:07    ls -la
    2014-08-27 17:13:09    cd .ash
    2014-08-27 17:16:27    ls
    2014-08-27 17:16:33    rm -rf advanced-shell-history/
    2014-08-27 17:16:35    ls
    2014-08-27 17:16:37    less postinstall.sh
    2014-08-27 17:16:57    sudo reboot -n

и та же история с использованием текущего рабочего каталога (и ничего ниже него):

vagrant@precise32:~$ ash_query -q RCWD
session
    where
        when                   what
1
    /home/vagrant/advanced-shell-history
        2014-08-27 17:11:34    nano ~/.bashrc
        2014-08-27 17:12:54    source /usr/lib/advanced_shell_history/bash
        2014-08-27 17:12:57    source /usr/lib/advanced_shell_history/bash
        2014-08-27 17:13:05    cd
    /home/vagrant
        2014-08-27 17:13:07    ls -la
        2014-08-27 17:13:09    cd .ash
    /home/vagrant/.ash
        2014-08-27 17:13:10    ls
        2014-08-27 17:13:11    ls -l
        2014-08-27 17:13:16    sqlite3 history.db
        2014-08-27 17:13:43    ash_query
        2014-08-27 17:13:50    ash_query -Q
        2014-08-27 17:13:56    ash_query -q DEMO
        2014-08-27 17:14:39    ash_query -q ME
        2014-08-27 17:16:26    cd
    /home/vagrant
        2014-08-27 17:16:27    ls
        2014-08-27 17:16:33    rm -rf advanced-shell-history/
        2014-08-27 17:16:35    ls
        2014-08-27 17:16:37    less postinstall.sh
        2014-08-27 17:16:57    sudo reboot -n

FWIW-я автор и сопровождающий проекта.

hcmnts-короткая версия функции

вот краткая версия в виде функции. Я также опубликовал один лайнер (оригинал) и более длинную функцию с несколькими добавленными функциями. Мне нравятся версии функций, потому что они не будут сбивать другие переменные в вашей среде, и они гораздо более читаемы, чем однострочные. Прочитайте запись для одного лайнера для получения дополнительной информации о том, как это работает и некоторые ограничения. Я разместил каждую версию в своем собственном ответе в чтобы все было более организованно.

чтобы использовать этот, сохраните его в файле под названием hcmnts в месте, как /usr/local/bin (можно chmod +x это если вы хотите), то источник ее в своем ~/.bashrc такой:

source /usr/local/bin/hcmnts

закомментируйте строку, которая устанавливает hcmntextra если вы не хотите дату и время (или вы можете изменить его формат или использовать другую команду, кроме date).

это все, что нужно.

#!/bin/bash
hcmnts() {
    # adds comments to bash history entries

    # the *S*hort version of hcmnt (which has many more features)

    # by Dennis Williamson
    # http://stackoverflow.com/questions/945288/saving-current-directory-to-bash-history
    # (thanks to Lajos Nagy for the idea)

    # INSTALLATION: source this file in your .bashrc

    # will not work if HISTTIMEFORMAT is used - use hcmntextra instead
    export HISTTIMEFORMAT=

    # HISTTIMEFORMAT still works in a subshell, however, since it gets unset automatically:

    #   $ htf="%Y-%m-%d %R "    # save it for re-use
    #   $ (HISTTIMEFORMAT=$htf; history 20)|grep 11:25

    local hcmnt
    local cwd
    local extra

    hcmnt=$(history 1)
    hcmnt="${hcmnt# *[0-9]*  }"

    if [[ ${hcmnt%% *} == "cd" ]]
    then
        cwd=$OLDPWD
    else
        cwd=$PWD
    fi

    extra=$(eval "$hcmntextra")

    hcmnt="${hcmnt% ### *}"
    hcmnt="$hcmnt ### ${extra:+$extra }$cwd"

    history -s "$hcmnt"
}
export hcmntextra='date +"%Y%m%d %R"'
export PROMPT_COMMAND='hcmnts'

джентльмен это работает лучше.. Единственное, что я не могу понять, как сделать скрипт не войти в системный журнал при входе в систему и войти в последнюю команду в истории. Но работает как шарм до сих пор.

#!/bin/bash

trackerbash() {
    # adds comments to bash history entries

    # by Dennis Williamson
    # http://stackoverflow.com/questions/945288/saving-current-directory-to-bash-history
    # (thanks to Lajos Nagy for the idea)

    #Supper Enhanced by QXT


    # INSTALLATION: source this file in your .bashrc

    export HISTTIMEFORMAT=
#    export HISTTIMEFORMAT='%F   %T    '

    local hcmnt
    local cwd
    local extra
    local thistty
    local whoiam
    local sudouser
    local shelldate
    local TRACKIP
    local TRACKHOST


            thistty=`/usr/bin/tty|/bin/cut -f3-4 -d/`
            whoiam=`/usr/bin/whoami`
            sudouser=`last |grep $thistty |head -1 | awk '{ print  }' |cut -c 1-10`
            hcmnt=$(history 1)
            hcmnt="${hcmnt# *[0-9]*  }"
            cwd=`pwd`



            hcmnt="${hcmnt% ### *}"
            hcmnt=" $hcmnt ${extra:+$extra }"

            shelldate=`date +"%Y %b %d %R:%S"`
            TRACKHOST=`whoami | sed -r "s/.*\((.*)\).*/\1/"`
            TRACKIP=`last |grep $thistty |head -1 | awk '{ print  }'`


            logger -p local1.notice -t bashtracker -i -- "$sudouser ${USER}: $thistty: $TRACKIP: $shelldate: $cwd : $hcmnt"
            history -w 

}
export PROMPT_COMMAND='trackerbash'

для тех, кто хочет этого в ЗШ у меня изменен реализация Джита Сукумарана и percol, чтобы разрешить интерактивный поиск по ключевым словам и извлечение либо команды, либо пути, в котором она была выполнена. Также можно отфильтровать повторяющиеся команды и скрыть поля (дата, команда, путь)

вот один лайнер того, что я использую. Вставляя его здесь, потому что это намного проще, и у меня нет проблем с историей за сеанс, я просто и хотите иметь историю с рабочим каталогом.

export PROMPT_COMMAND='if [ "$(id -u)" -ne 0 ]; then echo "$(date "+%Y-%m-%d.%H:%M:%S") $(pwd) $(history 1)" >> ~/.bash.log; fi'

Так как мой домашний dir, как правило, кросс-монтируется gluster thingy, это имеет побочный эффект быть историей всего, что я когда-либо делал. При желании добавить $(hostname) к команде echo выше... в зависимости от вашей рабочей среде.

даже с записями 100k grep более чем достаточно хорош. Не нужно SQLite регистрировать его. Просто не вводите пароли в командной строке, и Вы хороши. Пароли-это технология 90-х годов в любом случае!

кроме того, для поиска я склонен делать это:

function hh() {
    grep "" ~/.bash.log
}