Історія башів: "ігнорування" та "стирання" налаштування конфліктують із загальною історією протягом сеансів


84

Перш за все, це не дублікат жодних існуючих потоків на SE. Я прочитав ці дві теми ( 1-й , 2-й ) з кращої історії баш, але жодна з відповідей не працює - - До речі, я на Fedora 15.

Я додав наступне у .bashrcфайл у каталозі користувачів (/ home / aahan /), і він не працює. Хтось має підказку?

HISTCONTROL=ignoredups:erasedups  # no duplicate entries
HISTSIZE=1000                     # custom history size
HISTFILESIZE=100000                 # custom history file size
shopt -s histappend                      # append to history, don't overwrite it
PROMPT_COMMAND="history -a; history -c; history -r; $PROMPT_COMMAND"  # Save and reload the history after each command finishes

Гаразд, це те, що я хочу з історією баш (пріоритет):

  • не зберігайте дублікати, не стирайте жодних існуючих
  • негайно поділіться історією з усіма відкритими терміналами
  • завжди додайте історію, а не перезаписуйте її
  • зберігати багаторядкові команди як єдину команду (яка за замовчуванням вимкнена)
  • що за замовчуванням розмір історії та розмір файлу історії?

шишка! хтось? Нічого не працює. Чи може це бути проблемою з Fedora 15 (з Gnome 3 та працює на віртуальній машині Windows)?
its_me

Будь ласка, не "обробляйте" повідомлення тут. Якщо вони не отримують відповіді, вам потрібно запитати більш чітко, включити правильні шматочки контексту чи щось таке. Якщо вам потрібна увага в своїх публікаціях, ви можете видавати щедрості, які допоможуть привернути більше уваги людей.
Калеб

1
Ви впевнені, що навіть використовуєте bash? ( echo $SHELL). Чи працюють налаштування, якщо ви запускаєте їх вручну зі своєї відкритої оболонки? Очевидно, оскільки вони працюють для багатьох інших, налаштування правильні, ви просто неправильно реалізуєте їх. І жодна Fedora15 / Gnome3 /, що є віртуальною машиною, не має нічого спільного з реальною функцією bash.
Калеб

@Caleb, спочатку вибачте, що натрапив на пост. Також я намагався зробити все можливе, щоб бути дуже чітким. Ні, я не видав їх в оболонці. Я просто скопіював їх і вставив у .bashrcфайл. Це неправильно? Чи можете ви додати до цього повідомлення "відповідь" за допомогою фактичних команд оболонки? (будь ласка, потерпіть з моїм noob-ity.)
its_me

1
Все, що ви пишете в сценаріях або .bashrcARE фактичних команд оболонки. Сценарії - це лише ряд команд оболонки. Також редакція, яку ви нещодавно зробили, видалення exportшматочка була поганою ідеєю, яку слід дотримуватися.
Калеб

Відповіді:


119

Це насправді дуже цікава поведінка, і, зізнаюся, я дуже недооцінив це питання на початку. Але спочатку факти:

1. Що працює

Функціональність може бути досягнута кількома способами, хоча кожен працює трохи інакше. Зауважте, що в кожному випадку, щоб історія була "перенесена" на інший термінал (оновлений), потрібно натиснути Enterв терміналі, де він / вона хоче отримати історію.

  • варіант 1:

    shopt -s histappend
    HISTCONTROL=ignoredups
    PROMPT_COMMAND="history -a; history -n; $PROMPT_COMMAND"
    

    У цього є два недоліки:

    1. Під час входу (відкриття терміналу) остання команда з файлу історії зчитується двічі в буфер історії поточного терміналу;
    2. Буфери різних терміналів не синхронізуються з файлом історії.
  • варіант 2:

    HISTCONTROL=ignoredups
    PROMPT_COMMAND="history -a; history -c; history -r; $PROMPT_COMMAND"
    

    (Так, немає потреби shopt -s histappendта так, це має бути history -c в середині PROMPT_COMMAND) Ця версія має також два важливих недоліки:

    1. Файл історії потрібно ініціалізувати. Він повинен містити принаймні один не порожній рядок (може бути чим завгодно).
    2. historyКоманда може дати помилковий вихід - дивіться нижче.

[Редагувати] "І переможець ..."

  • варіант 3:

    HISTCONTROL=ignoredups:erasedups
    shopt -s histappend
    PROMPT_COMMAND="history -n; history -w; history -c; history -r; $PROMPT_COMMAND"
    

    Це наскільки це виходить. Це єдиний варіант одночасної роботи erasedupsі спільної історії. Це , мабуть, остаточне рішення всіх ваших проблем, Аахане.


2. Чому варіант 2, здається, не працює (або: що насправді не працює так, як очікувалося)?

Як я вже згадував, кожне з перерахованих вище рішень працює по-різному. Але найбільш оманливе тлумачення того, як працюють налаштування, виходить з аналізу результатів historyкоманди . У багатьох випадках команда може дати помилковий вихід. Чому? Тому що він виконується перед послідовністю інших historyкоманд, що містяться в PROMPT_COMMAND! Однак, використовуючи другий або третій варіант, можна стежити за .bash_historyзмістом вмісту (використовуючи, watch -n1 "tail -n20 .bash_history"наприклад), і бачити, що таке реальна історія.

3. Чому варіант 3 настільки складний?

Все лежить у тому, як erasedupsпрацює. Як зазначено в посібнику з bash, "(...) erasedupsпризводить до того, що всі попередні рядки, що відповідають поточному рядку, будуть видалені зі списку історії, перш ніж цей рядок буде збережено" . Отже, це дійсно те, чого хотіла ОП (і не просто, як я вважав раніше, щоб не було дублікатів, що з’являються послідовно ) . Ось чому кожна з history -.команд повинна або не може бути у PROMPT_COMMAND:

  • history -n повинен бути там , перш ніж history -wчитати з .bash_historyкоманд , збережених з будь-якого іншим терміналу,

  • history -w має бути там, щоб зберегти історію для зберігання та видалення дублікатів,

  • history -a його не слід розміщувати замість цього history -w, оскільки це не викликає стирання дублікатів,

  • history -cтакож потрібен, оскільки він запобігає збиттю буфера історії після кожної команди,

  • і , нарешті, history -rце необхідно для відновлення буфера історії з файлу, таким чином , нарешті , що робить історію спільну через термінальні сесії.


2
+1 для "Але найбільш оманлива інтерпретація того, як працюють налаштування, виходить з аналізу результатів команди" Історія ". Я думаю, що це суть питання ОП. Відмінна дедукція.
jasonwryan

2
Я нарешті побачив вашу думку. Під "дублікатами" ви мали на увазі щось інше, ніж я. Я зосередився лише на послідовностях однієї команди . Оновлена ​​моя відповідь - див. "Варіант 3". Крім того, для вашого випадку, щоб перевірити, як працює історія, ви насправді повинні використовувати watch "tail -n 20 .bash_history"замість tail -f .bash_history.
rozcietrzewiacz

2
Варіант 3 просто знищив усі мої 100 000 рядків історії :( (баш 3.2.25 (1) -випуск)
Феліпе Альварес

2
history -cтакож необхідний, оскільки він запобігає збиттю буфера історії після кожної команди. Чому трапляється ця коробка?
Пьотр Доброгост,

2
Ваше рішення 3 насправді не працює. Це надзвичайно глючно і залежить від порядку, який користувачі потрапляють у різні термінали. Це часто призводить до втрати команд, особливо при переключенні між терміналами вперед і назад. Джерело: спробував це.
6цефа

8

У вашій команді підказок ви використовуєте -cперемикач. Від man bash:

-c   Очистити список історії, видаливши всі записи

Щоб поділитися своєю історією з усіма відкритими терміналами, ви можете використовувати -n:

-n   Прочитайте рядки історії, не прочитані з файла історії, у поточний список історії. Це рядки, додані до файлу історії з початку поточного сеансу bash.

Розмір за замовчуванням також знаходиться в посібнику:

HISTSIZE Кількість команд, які слід запам'ятати в історії команд (див. ІСТОРІЯ нижче). Значення за замовчуванням - 500.

Щоб зберегти багаторядкові команди:

Cmdhist варіант оболонки, якщо він включений, змушує оболонку , щоб спробувати зберегти кожну лінію команди багаторядкового в одній і тій же записи журналу, додавши крапку з комою , коли це необхідно для збереження синтаксичної правильності. Опція літистської оболонки змушує оболонку зберегти команду із вбудованими новими рядками замість крапки з комою.

Крім того, не слід попередньо виконувати команди HIST * export- вони є лише базовими змінними, а не змінами середовища: HISTCONTROL=ignoredups:erasedupsдостатньо.


Отже, це export PROMPT_COMMAND="history -a; history -n; history -r; $PROMPT_COMMAND"правильно? Також, чи знаєте ви, як я можу зробити так, щоб файли історії зберігали багаторядкові команди як єдину команду (яка за замовчуванням вимкнена) ??
its_me

1
Так. Згідно з вказаною вище сторінкою man, shopt -s cmdhistрятуватиме рядки.
Jasonwryan

Гаразд, я спробував їх усіх. Схоже, HISTCONTROL=ignoredups:erasedupsце не працює. Я також спробував мати саме це у .bashrcфайлі (серед спеціальних функцій). Будь-яка ідея, що може бути не так? Я використовую Fedora 15 на віртуальній машині - - хост Windows 7.
its_me

Переконайтесь, що в інших файлах запуску, наприклад /etc/bashrc, .bash_profileтощо , немає нічого , що це перевищує.
jasonwryan

Я не бачу проблем із .bash_profileфайлом. Що стосується вмісту, який /etc/bashrcя розміщую тут, будь ласка, подивіться - pastebin.com/Uae6sE6s
its_me

8

Це те, що я придумав, і я задоволений цим поки що ...

alias hfix='history -n && history | sort -k2 -k1nr | uniq -f1 | sort -n | cut -c8- > ~/.tmp$$ && history -c && history -r ~/.tmp$$ && history -w && rm ~/.tmp$$'  
HISTCONTROL=ignorespace  
shopt -s histappend  
shopt -s extglob  
HISTSIZE=1000  
HISTFILESIZE=2000  
export HISTIGNORE="!(+(*\ *))"  
PROMPT_COMMAND="hfix; $PROMPT_COMMAND" 

ПРИМІТКИ:

  • Так, це складно ... але він видаляє всі дублікати і при цьому зберігає хронологію в кожному терміналі!
  • Моя HISTIGNOREігнорує всі команди, які не мають аргументів. Деяким людям це може не бути бажаним, і його можна залишати осторонь.


0

Це не працює, тому що ви забуваєте про:

 -n   read all history lines not already read from the history file
      and append them to the history list

Але, здається, history -nце просто баггі, коли export HISTCONTROL=ignoreboth:erasedupsдіє.

Дозволяє експериментувати:

$ PROMPT_COMMAND=
$ export HISTCONTROL=ignoreboth:erasedups
$ export HISTFILE=~/.bash_myhistory
$ HISTIGNORE='history:history -w'
$ history -c
$ history -w

Тут ми включаємо стирання дупів, перемикаємо історію на спеціальний файл, очищаємо історію. Після завершення всіх команд у нас є порожній файл історії та одна команда в поточній історії.

$ history
$ cat ~/.bash_myhistory
$ history
$ 1  [2019-06-17 14:57:19] cat ~/.bash_myhistory

Відкрийте другий термінал і також запустіть ці шість команд. Після того:

$ echo "X"
$ echo "Y"
$ history -w
$ history
  1  [2019-06-17 15:00:21] echo "X"
  2  [2019-06-17 15:00:23] echo "Y"

Тепер у вашій поточній історії є дві команди, а файл історії:

#1560772821
echo "X"
#1560772823
echo "Y"

Повернутися до першого терміналу:

$ history -n
$ history
1  [2019-06-17 14:57:19] cat ~/.bash_myhistory 
2  [2019-06-17 15:03:12] history -n

Так ... жодна echoкоманда не читається. Знову перейдіть на другий термінал і:

$ echo "Z"
$ history -w

Тепер файл історії такий:

#1560772821
echo "X"
#1560772823
echo "Y"
#1560773057
echo "Z"

Знову перейдіть на перший термінал:

$ history -n
$ history
  1  [2019-06-17 14:57:19] cat ~/.bash_myhistory 
  2  [2019-06-17 15:03:12] history -n
echo "Z"

Ви можете бачити, що echo "Z"команда об'єднана в history -n.

Ще одна помилка через те, що команди читаються з історії за номером команди, а не за командним часом. Я очікую, що echoв історії з'явилися інші команди


0

erasedups не обрізає (наприклад, chomp у деяких мовах) провідних та кінцевих пробілів. Це помилка. Також erasedups не видаляє всі попередні записи.

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