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

7

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

Любое руководство с благодарностью.

Спасибо джуди

Джуди
источник
3
Ваш вопрос немного сбивает с толку. Что вы подразумеваете под «не похоже, что он работает в файле bash, но отлично работает при выполнении в командной строке»? Вы имеете в виду, что пытаетесь сохранить историю команд из исполняемого скрипта bash? Как вы хотите сохранить, какие команды были выполнены скриптом? Сам сценарий является историей в этом случае.
Стивен
6
Или вы хотите вывести историю bash конкретного пользователя? Вы можете просто прочитать ~/.bash_historyфайл пользователя .
Arronical
1
@ Arronical заметьте, что это будет работать, только если пользователь использует Bash в качестве оболочки, что не всегда так.
1
@ p0llard Конечно, я подскочил с предположением, что, как и в сценарии Bash, это будет Bash в качестве оболочки пользователя, но, как вы сказали, это может быть не так. Хорошая детализация и предыстория в вашем ответе.
Arronical

Ответы:

11

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

Запустите скрипт с помощью 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будет «читать и выполнять команды из аргумента имени файла в текущем контексте оболочки», так что любые команды, как cdвнутри, будут влиять на ваш текущий сеанс. Если бы вы запустили приведенный выше сценарий, передав его sourceвам, вы обнаружите, что вы оказались в корневом каталоге после его запуска .

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

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


источник
Очень интересно читать. Я всегда удивлялся «пропущенным» командам истории, теперь я знаю почему. Спасибо!
Тико
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 "$1" > 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
источник