Как сохранить историю терминала в файле из файла bash?

7

Я пытаюсь создать сценарий bash, который сохранит историю терминала в файле hist.txt. Использование history > hist.txt , похоже, не работает в сценарии bash, но отлично работает при выполнении в командной строке.

Любые рекомендации приветствуются.

Спасибо. Judy

    
задан Judy 29.09.2016 в 13:58
источник

2 ответа

10

Короткий ответ

Запустите скрипт с source или . :

source ./script_name.sh

или

. ./script_name.sh

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

Длинный ответ

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

#!/bin/bash

cd /
ls

Если вы запустите это, вы получите результат примерно так:

bin  boot  dev  etc  home  lib  lib64  lost+found  media  mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var

Но вы заметите, что после запуска скрипта вы все еще находитесь в любом каталоге, в котором вы были, прежде чем запускаете его: cd / внутри скрипта фактически не повлияло на ваш сеанс - это повлияло только на контекст, который был запущен скрипт, который создается для запуска сценария и уничтожается после его возврата.

Команда source будет «читать и выполнять команды из аргумента filename в текущем контексте оболочки», поэтому любые команды, такие как cd внутри нее, будут влиять на текущий сеанс. Если вы должны были запустить сценарий выше, передав его в source , вы обнаружите, что закончите внутри корневого каталога после его запуска.

В этом случае проблема заключается в том, что команда history дает вам историю для текущего контекста оболочки; контекст оболочки, в котором работает ваш скрипт без использования source , не имеет истории, поэтому он ничего не пишет в выходной файл. Если вы используете source , он будет выполняться в правильном контексте и будет работать как ожидалось.

NB: source - это встроенная оболочка, а не программа per se - в Bash, source является синонимом . , но в некоторых оболочках только . будет работа - я использовал source в этом ответе, потому что его легче читать, чем . , но для максимальной совместимости следует использовать . .

    
ответ дан p0llard 29.09.2016 в 15:05
источник
10

Прежде всего, обратите внимание, что ваша история уже находится в файле. Если вы используете bash, его имя обычно ~/.bash_history . Более конкретно, это то, что вы установили переменной HISTFILE . Если вы хотите скопировать его в другой файл, просто запустите cat "$HISTFILE" > hist.txt

Теперь, почему команда history не работает в сценарии оболочки bash, это потому, что скрипты запускаются в неинтерактивной дочерней оболочке вашего текущего сеанса оболочки. Детские оболочки не наследуют всю родительскую среду (поэтому не все заданные переменные), а только переменные, которые были экспортированы. Чтобы проиллюстрировать, приведенный ниже сценарий будет отображать значение переменной $var :

#!/bin/bash
echo "$var"

Теперь установите $var на что-то и запустите скрипт:

$ var="foo"
$ foo.sh
VAR: 

Затем сначала экспортируйте переменную:

$ var="foo"
$ export var
$ foo.sh
VAR: foo

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

Как я упоминал ранее, история сохраняется в файле, на который указывает переменная $HISTFILENAME . Поскольку он не экспортируется по умолчанию, он не устанавливается при запуске скрипта:

$ cat foo.sh
#!/bin/bash
echo "HISTFILE: $HISTFILE"
$ ./foo.sh
HISTFILE:
$ echo $HISTFILE
/home/terdon/.bash_history

Как вы можете видеть в приведенном выше примере, переменная HISTFILE устанавливается в моем обычном сеансе оболочки, но при запуске скрипта она пуста.

Итак, чтобы получить историю, у вас есть несколько вариантов:

  1. Значение по умолчанию HISTFILE равно $HOME/.bash_history . Если вы не изменили это, вы можете просто запустить эту команду в своем скрипте:

    cat "$HOME/.bash_history" > history
    
  2. Вы можете передать переменную $HISTFILE в свой скрипт и cat , которые:

    #!/bin/bash
    cat "" > history
    

    Сохраните выше как foo.sh и выполните следующие действия:

    ./foo.sh "$HISTORY"
    
  3. Убедитесь, что переменная экспортирована. Добавьте эту строку в свой ~/.bash_profile (если она существует) или ~/.profile (если ~/.bash_profile не существует):

    export HISTFILE
    

    Затем выйдите из системы и снова войдите в систему, и вы должны будете запустить history > hist.txt из сценария, как ожидалось. Это связано с тем, что export VAR означает «сделать $ VAR доступным для дочерних оболочек». С практической точки зрения это означает, что значение HISTFILE будет унаследовано неинтерактивной оболочкой, используемой для запуска скрипта.

    Теперь, когда HISTFILE будет установлено, он не был прочитан оболочкой, запускающей скрипт. Итак, чтобы заставить его работать, сначала вам нужно прочитать его с помощью history -r . Весь скрипт будет выглядеть так:

    $!/bin/bash
    history -r
    history > hist.txt
    

    В качестве альтернативы просто экспортируйте его вручную перед запуском скрипта:

    $ export HISTFILE
    

    Но вам все равно нужно history -r в скрипте.

  4. Вы можете использовать source , как было предложено ответом @ p0llard .

ответ дан terdon 29.09.2016 в 15:08
источник

Ознакомьтесь с другими вопросами по меткам