Когда возможна многострочная запись истории (aka lithist) в bash?

проблема ушла с новыми версиями ядра linux :). Я не видел регрессии мощности со времен ubuntu 14.

8
23.03.2017, 20:12
5 ответов

A \<новая строка> не является правильным способом получить <новая строка> в истории.

Память

Давайте работать только со строками истории, так как они хранятся в памяти оболочки (не на диске).

Давайте наберем пару команд, как вы:

$ echo -n "this is a test for a ";\
> echo "two line command"

Что было сохранено в памяти в виде только что написанной строки?

$ history 2
514  echo -n "this is a test for a ";echo "two line command"
515  history 2

Как видите, «продолжение строки», обратная косая черта, за которой следует перевод строки, было удалено.
Как и должно быть (из man bash):

Если появляется пара \, а обратная косая черта не заключена в кавычки, \ рассматривается как продолжение строки (то есть удаляется из входного потока и эффективно игнорируется).

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

$ echo " A test of 
> a new line"
A test of 
a new line

И в этот момент история отразит следующее:

$ history 2
  518  echo "A test of
a new line"
  519  history 2

Настоящая многострочная команда:

Один из возможных примеров многострочной команды это:

$ for a in one two
> do echo "test $a"
> done
test one
test two

Который будет свернут в одну строку истории, если cmdhist установлен :

$ shopt -p cmdhist lithist
shopt -s cmdhist                                                                                                       
shopt -u lithist

$ history 3
   24  for a in one two; do echo "test $a"; done                                                                       
   25  shopt -p cmdhist lithist                                                                                        
   26  history 3     

Числа для каждой команды изменились, потому что в какой-то момент я очистил историю (в памяти) с помощью история -c.

Если вы отключите cmdhist, вы получите следующее:

$ shopt -u cmdhist
$ for a in one two
> do echo "test $a"
> done
test one
test two

$ history 5
    5  shopt -u cmdhist
    6  for a in one two
    7  do echo "test $a"
    8  done
    9  history 5

Каждая строка (не полная команда) будет находиться на отдельной строке в истории.

Даже если установлен lithist:

$ shopt -s lithist
$ for a in one two
> do echo "test $a"
> done
test one
test two
$ history 5
   12  shopt -s lithist
   13  for a in one two
   14  do echo "test $a"
   15  done
   16  history 5

Но если установлены оба:

$ shopt -s cmdhist lithist
$ for a in one two
> do echo "test $a"
> done

$ history 5
   23  history 15
   24  shopt -p cmdhist lithist
   25  shopt -s cmdhist lithist
   26  for a in one two
do echo "test $a"
done
   27  history 5

Команда for была сохранена как многострочная команда с символом новой строки вместо точки с запятой. (;). Сравните с приведенным выше, где lithist не был установлен.

Диск

Все вышесказанное объяснялось с помощью списка команд, хранящихся в памяти оболочки. Команды на диск не записывались. Файл (по умолчанию) ~/.bash_history не был изменен.

Этот файл будет изменен при выходе из работающей оболочки. В этот момент история перезапишет файл (если не установлено histappend) или будет добавлена ​​в противном случае.

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

export PROMPT_COMMAND='history -a'

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

Теперь давайте приступим к работе с cmdhist и lithist. Это не так просто, как может показаться. Но не волнуйтесь, через мгновение все станет ясно.

Допустим, вы нашли время, чтобы ввести все приведенные ниже команды (здесь нет ярлыка, нет псевдонима, нет функции, вам нужны настоящие команды, извините).
Сначала очистить всю историю в памяти (история -c) и на диске (сделать резервную копию) (история -w), а затем попробовать три раза:

  • Со значениями по умолчанию cmdhist (установлено) и lithist (не установлено).
  • При обоих установленных
  • При обоих неустановленных
  • Установка lithist при неустановленном cmdhist не имеет смысла (можно проверить).

Список команд для выполнения:

$ history -c ; history -w           # Clear all history ( Please backup).

$ shopt -s cmdhist; shopt -u lithist
$ for a in one two
> do echo "test $a"
> done

$ shopt -s cmdhist; shopt -s lithist
$ for a in one two
> do echo "test $a"
> done

$ shopt -u cmdhist; shopt -u lithist
$ for a in one two
> do echo "test $a"
> done

Вы закончите этим (в памяти):

$ history
    1  shopt -s cmdhist; shopt -u lithist
    2  for a in one two; do echo "test $a"; done
    3  shopt -s cmdhist; shopt -s lithist
    4  for a in one two
do echo "test $a"
done
    5  shopt -u cmdhist; shopt -u lithist
    6  for a in one two
    7  do echo "test $a"
    8  done
    9  history

Три многострочные команды заканчиваются следующим образом:

  • одна в строке с номером 2 (одна отдельная строка, одна команда).
  • один в многострочном номере 4 (одна команда в нескольких строках)
  • один в нескольких строках с номером от 6 до 8

Хорошо, но что происходит в файле? сказать это уже ....

наконец, в файле:

Просто, запишите в файл и просмотрите его, чтобы увидеть это:

$ history -w ; cat "$HISTFILE"
shopt -s cmdhist; shopt -u lithist
for a in one two; do echo "test $a"; done
shopt -s cmdhist; shopt -s lithist
for a in one two
do echo "test $a"
done
shopt -u cmdhist; shopt -u lithist
for a in one two
do echo "test $a"
done
history
history -w ; cat "$HISTFILE"

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

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

Имеется только один разделитель (новая строка), каждая строка считывается как одна команда.

Есть ли решение этого, да, использовать дополнительный разделитель.
Тип HISTTIMEFORMAT делает это.

HISTTIMEFORMAT

Когда для этой переменной задано какое-либо значение, время выполнения каждой команды сохраняется в файле как секунды с начала эпохи (да, всегда секунды) после комментария (# ) персонаж.

Если мы установим переменную и перепишем файл ~/.bash_history, то получим следующее:

$ HISTTIMEFORMAT='%F'
$ history -w ; cat "$HISTFILE"
#1490321397
shopt -s cmdhist; shopt -u lithist
#1490321397
for a in one two; do echo "test $a"; done
#1490321406
shopt -s cmdhist; shopt -s lithist
#1490321406
for a in one two
do echo "test $a"
done
#1490321418
shopt -u cmdhist; shopt -u lithist
#1490321418
for a in one two
#1490321418
do echo "test $a"
#1490321420
done
#1490321429
history
#1490321439
history -w ; cat "$HISTFILE"
#1490321530
HISTTIMEFORMAT='%FT%T '
#1490321571
history -w ; cat "$HISTFILE"

Теперь можно сказать, где и какая строка является многострочной.

Формат '%FT%T' показывает время, но только при использовании команды истории:

$ history
    1  2017-03-23T22:09:57 shopt -s cmdhist; shopt -u lithist
    2  2017-03-23T22:09:57 for a in one two; do echo "test $a"; done
    3  2017-03-23T22:10:06 shopt -s cmdhist; shopt -s lithist
    4  2017-03-23T22:10:06 for a in one two
do echo "test $a"
done
    5  2017-03-23T22:10:18 shopt -u cmdhist; shopt -u lithist
    6  2017-03-23T22:10:18 for a in one two
    7  2017-03-23T22:10:18 do echo "test $a"
    8  2017-03-23T22:10:20 done
    9  2017-03-23T22:10:29 history
   10  2017-03-23T22:10:39 history -w ; cat "$HISTFILE"
   11  2017-03-23T22:12:10 HISTTIMEFORMAT='%F'
   12  2017-03-23T22:12:51 history -w ; cat "$HISTFILE"
   13  2017-03-23T22:15:30 history
   14  2017-03-23T22:16:29 HISTTIMEFORMAT='%FT%T'
   15  2017-03-23T22:16:31 history
   16  2017-03-23T22:16:35 HISTTIMEFORMAT='%FT%T '
   17  2017-03-23T22:16:37 history
17
27.01.2020, 20:10

Это не похоже на многострочную команду (потому что вы избежали возврата). Если вы сделаете это с реальной прибылью, разница будет.

$ for i in /tmp/g*
> do echo $i
> done
/tmp/gigabyte
$ shopt -s lithist
$ for i in /tmp/g*
> do echo $i
> done
/tmp/gigabyte
$ history 
[...]
  517  for i in /tmp/g* ; do echo $i ; done
  518  shopt -s lithist
  519  for i in /tmp/g*
do echo $i
done
  520  history
3
27.01.2020, 20:10

iTerm отлично обрабатывает несколько команд -строк, он сохраняет несколько команд строк -как одну команду, затем мы можем использовать Cmd + Shift + ; для навигации по истории. Дополнительные советы по iTerm см. на странице Эффективная работа с iTerm.

0
27.01.2020, 20:10

В то время как строки продолжения(\в конце строки )кажутся лишенными несмотря ни на что. Я понял, что есть два альтернативных способа сделать продолжение:

  1. Цитаты. Подстановка команды. Я предпочитаю это последнему

    $ echo "1st line";`
    > `echo "2nd line"
    1st line
    2nd line
    
    $ history 2
      507  echo "1st line";`
    `echo "2nd line"
      508  history 2
    
  2. Знаки доллара. Все еще злоупотребляет подстановкой команд.

    $ echo "1st line";$(
    > ) echo "2nd line"
    1st line
    2nd line
    
    $ history 2
      501  echo "1st line";$(
    ) echo "2nd line"
      502  history 2
    

Ага. Не очень обаятельный . Хотя, если подумать, когда мы думали, что слэш в EOL был красивым?

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

Самое интересное, что он работает даже с shopt -u lithist. Хотя запуск нового сеанса bash, который загружает историю из ~/.bash_history, приведет к их расщеплению.

0
27.01.2020, 20:10

Я пытался shopt -s lithist cmdhist.

Но после выхода из системы и входа в систему история восстановления из ~/.bash_historyпо-прежнему была разделена на несколько строк:

 1953  2019-05-23 16:57:53 shopt -s cmdhist; shopt -s lithist
 1954  2019-05-23 16:57:58 for i in 1 2 3
 1955  2019-05-23 16:58:34 do echo $i
 1956  2019-05-23 16:58:34 done
 1957  2019-05-23 16:58:08 history 5
 1958  2019-05-23 16:58:27 history -a
 1959  2019-05-23 16:54:12 history 10 | less 

Ожидается ли такое поведение?

Ниже приводится мое содержание~/.bash_history:

#1558601873
shopt -s cmdhist; shopt -s lithist
#1558601878
for i in 1 2 3
do echo $i
done
#1558601888
history 5
#1558601907
history -a
#1558601652
history 10 | less 

решение

я решаю эту проблему, удаляя старую ~/.bash _историю, тогда многострочная история работает нормально; даже после выхода из системы и входа в систему.

    1  2019-06-12 13:53:11 \rm.bash_history
    2  2019-06-12 13:53:27 fx mcd
    3  2019-06-12 13:53:28 mcd () 
{ 
    mkdir $@;
    cd $1
}
    4  2019-06-12 14:55:14 nmcli-restart-hotspot -s
    5  2019-06-12 21:34:35 ssh lab
    6  2019-06-12 23:38:45 history  | less 
0
27.01.2020, 20:10

Теги

Похожие вопросы