multiline command chunks in bash history into multiple lines
Solution 1:
I am using GNU bash, version 5.0.3(1)-release on Ubuntu 19.10. I checked and confirmed the issue described in your question exists.
I then solved it using the following steps. After that I exited bash multiple times and confirmed the problem is solved on my system. Multi-line commands are saved to the ~/.bash_history
file, retrieved and executed correctly.
Solution:
Please edit your ~/.bashrc
file or create it if it does not exist.
Copy and paste the following three lines into it and save it:
shopt -s cmdhist
shopt -s lithist
HISTTIMEFORMAT='%F %T '
From bash man-pages:
cmdhist:
If set, bash attempts to save all lines of a multiple-line command in the same history entry. This allows easy re-editing of multi-line commands.
lithist:
If set, and the cmdhist option is enabled, multi-line commands are saved to the history with embedded newlines rather than using semicolon separators where possible.
However, cmdhist
and lithist
are useful while the shell is still open and working from memory. When you exit the shell, the commands are saved into the ~/.bash_history
file as single lines without any indication as to where a multi-line command starts or ends and then the working memory is cleared. When you run the shell again these lines in the bash history file (including the multi-line commands) will be read one line at a time and each line will be treated and loaded to working memory as a single command even though it could be a part of a multi-line command because the ~/.bash_history
file will look like this:
nano .bashrc
exit
history
for i in {1..10}
do
echo $i
done
cat .bash_history
exit
history
awk '
{ print $1}' <<<'first last'
history
exit
Hence the need for HISTTIMEFORMAT
which will act as a delimiter to separate each command from an other based on its timestamp, be it a single line or a multi-line command. So the ~/.bash_history
file will look like this:
nano .bashrc
#1581635697
exit
#1581635709
history
#1581635729
for i in {1..10}
do
echo $i
done
#1581635743
cat .bash_history
#1581635757
exit
#1581635773
history
#1581635794
awk '
{ print $1}' <<<'first last'
#1581635801
history
#1581635808
exit
From bash man-pages:
HISTTIMEFORMAT:
If this variable is set and not null, its value is used as a format string for strftime(3) to print the time stamp associated with each history entry displayed by the history builtin. If this variable is set, time stamps are written to the history file so they may be preserved across shell sessions. This uses the history comment character to distinguish timestamps from other history lines.
From now on multi-line commands will be retrieved, treated and loaded into working memory as a whole (without breaking them into single lines and treating each line as a separate command) and the history
command output will look like this (even after restarting bash):
raffa@Laptop:~$ history
1 2020-02-14 05:25:19 nano .bashrc
2 2020-02-14 05:25:38 exit
3 2020-02-14 05:25:50 history
4 2020-02-14 05:27:50 for i in {1..10}
do
echo $i
done
5 2020-02-14 05:28:05 cat .bash_history
6 2020-02-14 05:28:14 exit
7 2020-02-14 05:28:27 history
8 2020-02-14 05:28:55 awk '
{ print $1}' <<<'first last'
9 2020-02-14 05:29:06 history
10 2020-02-14 05:29:16 exit
11 2020-02-14 05:29:27 history
And multi-line commands will be correctly retrieved, displayed and executed after exit.
Notice:
- You will need to restart your current session of bash after editing and saving the
~/.bashrc
file to activate the changes. - If your current
~/.bash_history
file or bash working memory already contain history lines with formatting errors, you might need to delete (Please back up first) your current bash history by runninghistory -w; history -c
in the terminal which will permanently delete all your current bash history.
Best of luck