Як зберегти історію терміналу у файл із файлу bash?


7

Я намагаюся створити bash-скрипт, який збереже історію терміналу у файл під назвою hist.txt. Використання, history > hist.txtздається, не працює в скрипті bash, але працює добре, коли виконується в командному рядку.

Будь-які вказівки високо цінуються.

Дякую, Джуді


3
Ваше запитання трохи заплутане. Що ви маєте на увазі під "не здається, що працює у файлі bash, але працює добре, коли виконується в командному рядку"? Ви маєте на увазі, що ви намагаєтеся зберегти історію ваших команд із скрипту bash, який виконується? Як ви хочете зберегти, які команди були виконані скриптом? Сам сценарій - це історія в даному випадку.
Стівен

6
Або ви хочете вивести історію башів певного користувача? Ви можете просто прочитати ~/.bash_historyфайл користувача.
Арронічний

1
@Arronical зауважте, що це спрацює лише в тому випадку, якщо користувач використовує Bash як свою оболонку, що не завжди так.

1
@ p0llard Звичайно, я стрибнув з припущенням, що як це було в сценарії Bash, це буде Bash як оболонка користувача, але це може бути не так, як ви вже говорили. Хороша деталізація та інформація у вашій відповіді BTW.
Арронічний

Відповіді:


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його використовуєте, він буде виконуватися у правильному контексті та працюватиме як очікувалося.

Примітка: sourceвбудована оболонка, а не програма сама по собі - в Bash sourceє синонімом ., але в деяких оболонках .буде працювати тільки - я використовував sourceцю відповідь, тому що її легше читати, ніж .для максимальної сумісності .слід бути використаним.


Дуже цікаво читати. Я завжди замислювався над "відсутніми" командами історії, тепер я знаю, чому. Дякую!
Тико

10

Перш за все, зауважте, що ваша історія вже є у файлі. Якщо ви використовуєте bash, його назва зазвичай ~/.bash_history. Більш конкретно, це все, що ви встановили змінну HISTFILE. Якщо ви хочете скопіювати його в інший файл, просто запустітьcat "$HISTFILE" > hist.txt

Тепер, чому historyкоманда не працює в скрипті bash shell, це тому, що сценарії виконуються в неінтерактивній дочірній оболонці вашого поточного сеансу оболонки. Дочірні оболонки не успадковують все батьківське середовище (тому не всі встановлені змінні), лише ті змінні, які були експортовані. Для ілюстрації, скрипт, наведений нижче, буде відповідати значенню змінної $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 .

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.