|
Softpanorama
(slightly skeptical)
Open Source Software Educational Society |
May the
source be with you,
but remember the KISS principle ;-)
|
Shell Command Line History Substitution
"Those who cannot remember the past are condemned to repeat
it."
George Santayana (1863-1952)
|
All modern shell have mechanism of working with history of commands that
was originally introduced in C-shell. Famous quote "Those who cannot
remember the past are condemned to repeat it" has pretty literal
meaning here :-).But the methods of working with command history that were
created before current terminals were available now looks outdated. You
need to look at OFM like midnight commander for more modern ways.
Bash saves commands entered from your terminal device to a history file.
If set, the HISTFILE variable value is the name of the history file.
If the HISTFILE variable is not set or cannot be written, the default
name is used.
Control of the behavior of the command history is provided jointly by
bash and the readline library. Bash provides four variables ($HISTFILE,
$HISTSIZE, $HISTCONTROL and $HISTIGNORE) to control
the behavior of the history list:
History can be browsed using arrow commands, but more efficient way is to
use Ctrl-R for anything but previous
half-dozen of commands. Ctrl-R mechanism
provides search in history:
- typed characters can be in any place of the command
- will autocomplete as soon as there’s a match to a history entry,
then you just need to hit enter to reexecute the command
Bash supports C-shell command and argument reuse capabilities (so called
bang commands): If you know exact prefix for the command that you executed
recently you can reuse it without manually browsing history by typing !
followed by the first few letters of the command.
- $ !n --Will execute
the line n of the history record.
- $ !-n --Will execute
the command n lines back.
- $ !! --Will execute
the last command. Same as !-1 or "up-arrow + return"
- !gzip -- will
reexecute the most recent gzip command (string from the start)
- !?etc.gz – same as
above but the unique string doesn't have to be at the start of the command.
You can identify command by a unique string appearing anywhere in the
command
What is more important and convenient is that you can extract arguments
from previous commands
- !!:1 designates the
first argument of the last command.
- !!:$ designates the
last argument of the preceding command. This may be shortened to !$.
As you noticed there are a lot of features. So learning them you need
to know were to stop as return of investment quickly diminishes after a
half-dozen and can became negative: often composing a new command using
mouse and cut and paste mechanism is more efficient then old fashioned way.
Here is more a compete reference taken from Robbins Bash Quick Reference
card:
History expansion is similar to csh ’s. It is
enabled by default in interactive shells. History expansion
happens before the shell breaks the input into words,
although quoting is recognized and quoted text is
treated as one history ‘‘word’’. History substitution
is performed on history events
, which consist of an event designator (which previous
line to start with), a word designator (which word from that
line to use, starting with zero), and one or more optional modifiers
(which parts of the words to use).
Colons separate the three parts, although the colon
between the event designator and word designator may be omitted when
the word designator begins with ˆ , $ , * ,
− , or % . Each modifier is separated from the nextone with
a colon. The histchars variable specifies the start-of-history
and quick substitution characters, and also the comment character that
indicates that the rest of a line is a comment. The previous command
is the default event if no event designator is supplied.
The event designators are:
start a history substitution
!
n -- command line n
!−
n -- current line minus n (
n previous)
!! --
the previous command
!
str -- most recent command line starting
withstr
!?
str [ ? ] -- most recent command
line containing str
!# --
the entire command line typed so
far
ˆ
old ˆ new ˆ quick
substitution: repeat last command changing old to new
The word designators are:
the zero’th word (command name)
n word n
ˆ the first argument, i.e., word one
$ the last argument
% the word matched by the most recent
!? str ? search
x − y words x through
y . −y is short for 0−y
* words 1 through the last (like 1−$
)
n * words n through the last
(like n −$ )
n −words n through the next
to last
The modifiers are:remove all but the suffix of a filename
g make changes globally, use with s
modifier, below
h remove the last part of a filename, leaving
the ‘‘head’’
p print the command but do not execute it
q quote the generated text
r remove the last suffix of a filename
s/ old / new /
substitute new for old in the text. Any delimiter
may be used. An & in the replacement means the value
of old. With empty old , use last old ,
or the most recent !? str ? search if there
was no previous old
t remove all but the last part of a filename,leaving
the ‘‘tail’’
x quote the generated text, but break into
words at blanks and newline
& repeat the last substitution
Different people learn different ways to work with shell so the set of
features one adopts is usually quite individual. For example I never learned
to use internal search shell and always prefer to use external history search
via grep. For me there are just too many features to learn in Unix shells.
If I do not use some feature on a regular basis my skills quickly
deteriorate to the extent that I read this page with great interest :-).
Then, shamed by my own ignorance, I relearn some trick again and forget
them in a couple of months. And this cycle looks like an infinite loop.
In this sense the famous quote "Those who cannot remember the past are condemned
to repeat it." has a different, more menacing meaning: shell
does suffer from
Creeping featurism:
1. Describes a systematic tendency to load more /instinct.org/texts/jargon-file/jargon_21.html#TAG605">
feeping creaturism. "You know, the main problem with
BSD Unix has always been creeping featurism."
2. More generally, the tendency for anything complicated to become
even more complicated because people keep saying "Gee, it would be even
better if it had this feature too". (See
feature.) The result is usually a patchwork because it grew one
ad-hoc step at a time, rather than being planned. Planning is a lot
of work, but it's easy to add just one extra little feature to help
someone ... and then another ... and another.... When creeping featurism
gets out of hand, it's like a cancer.
Usually this term is used to describe computer programs, but it could
also be said of the federal government, the IRS 1040 form, and new cars.
A similar phenomenon sometimes afflicts conscious redesigns; see
second-system effect. See also
creeping elegance.
Here is later definition from
Wikipedia:
Creeping featurism, or creeping featuritis, is a phrase
used to describe
software
which over-emphasizes new
features
to the detriment of other
design goals, such as
simplicity,
compactness,
stability,
or
bug reduction. The term is often
spoonerized as feeping creaturism, a term intended to bring
the image of the encroaching features as small, seemingly benign animals
that creep into a program, making their trademark noises and demanding
their own space, soon taking over the entire project.
Creeping featurism is often accompanied by the mistaken belief that
"one small feature" will add zero incremental cost to a project, where
cost can be money, time, effort, or energy. A related term, feature
creep, describes the tendency for a software project's completion
to be delayed by the temptation to keep adding new features, without
a specific goal.
Due to creeping featurism there some built-in limits in productivity
achievable with any old technology. And often the way to raise productivity
is to switch to a newer technology. If you are interested is using shell
history you might be also interested in
orthodox file managers
that represent visual extension of the shell and as such greatly simplify
the work of system administrator and tremendously raise the productivity.
For Linux the most popular orthodox file manger is probably
Midnight commander.
Another way to imporve your productivity is to learn to use
screen
By default, the Korn shell or POSIX shell saves the text of the last
128 commands entered from a terminal device. The history file size (specified
by the HISTSIZE variable) is not limited, although a very large history
file can cause the Korn shell to start up slowly. Korn shell traditionally
uses the fc built-in command to list or edit portions of the history
file. It is usually aliased to history. To select a portion of the file
to edit or list, specify the number or the first character or characters
of the command. You can specify a single command or range of commands.
Still at least some of the capabilities provided by history substitution
mechanism remains to be very useful although complex operations for modifying
those commands (that are too rarely needed to justify the learning curve)
are simpler to do via cut and paste. You need to activate in-line editing
to be able to modify the command line.
To activate in-line editing you must have the EDITOR variable set to
vi or emacs. You may use the set -o vi or set -o
emacs command to select an in-line edit mode. This informs the shell
you want to be in in-line edit mode on each command line.
Among many other innovations, the C Shell introduced innovative approach
to using history file that is now more or less completely replicated in
bash. That is, you type in a command and the shell locates the command line
in the history file and performs the editing commands you specified. Each
command line in the history file is referenced by an event number. For example,
the following output is from the history command:
-
1 vi antispam105.pl
-
2 perl -c antispam105.pl
-
3 cp antispam105.pl
/usr/local/etc
-
4 find /spam/Spam_archive
-name "nobody" -print
-
5 vi apiprog.c
Event number 1 references the command line
"vi antispam105.pl" The command,
!3
reexecutes the "cp antispam105.pl /usr/local/etc"
command. There are two more useful shortcuts:
!string runs the most recent command beginning
with the string you specify.
- A !! refers to the last command in the history
list.
You can modify the command on the fly using search-and-replace type modifier
s/old/new/ (or s^old^new^ -- the delimiter is
actually arbitrary) but I never managed to make a use of this
feature.
More useful is the ability to specify the last argument of the prev command.
!!:$ designates the last word of the preceding command. This
may be shortened to !$. The addressing remings vi and
as in vi you can work with any command in history, not only the last.
Similarlity you can retrieve not only the last work but any word. For
example, !find:5 displays the fifth word from the last command
beginning with !find, while !find:$ would display
the last word from the same command. Please note that !find:*
is same as !find:1-$ - both resulting in the complete command
except for the first word. You type new command with the same arguments
that way.
Again I was never able to use this feature on regular basis and always
slipped to printing the whole command and then assembling new copying the
relevant parts with the mouse.
Entering the history command without any switches displays
the full history list with line numbers. If that's too much information,
enter history N where N is the number of previously executed
commands you want displayed.
C-shell style incremental search of the history list is possible
via ctrl-r or ctrl-s (the latter performs
a forward search).
You can grep last 100 or more commands in history for the commands you
want, for example:
history 100 | grep '^cd'
But it is better to create a shell a special function (with the name
like hs) to do that (this function can be made shell independent if
all RC scripts for your shells export the location of history file in the
same variable for example HISTFILE.
If you use shells other then bash you may need explicitly export a variable
that points to your shell history in you RC file. For example:
export HISTFILE="$HOME/.history"
export HISTIGNORE="&:ls:ll:cd \-:ls -l:cd .."
export HISTCONTROL=erasedups
and a function like:
function hs {
grep $1
$HISTORY
}
Shell history issues became more complex if there are multiple administrators
on a particular server. The best way to solve this problem is to individualize
shell history files for root based on original id of the user.
Notes:
- This is a Spartan WHYFF (We Help
You For Free) site written by people for whom English
is not a native language.
Some amount of grammar and spelling errors should be
expected.
- The site contain some broken links
as it develops like a living tree...
Please try to use Google, Open directory,
etc. to find a replacement link (see
HOWTO search the WEB for details). We would appreciate
if you can
mail us a correct link.
|
|
|
|
Bash provides a couple of
methods for searching the command history. Both are useful in different
situations. The first method is to simply type history,
find the number of the command you want and then type
!N where "N" is the number of the command you'd like to execute.
(:p works here too.) The other method is a tad more
complex but also adds flexibilty. ^r (ctrl-r) followed
by whatever you type will search the command history for that string.
The bonus here is that you're able to edit the command line you've searched
for before you send it down the line. While the second method is more
powerful, when doing some redundant task, it's much easier to remember
!22 than it is to muck with ctrl-r type searches or
even the arrow keys.
Bang dollar-sign
!$
is the "end" of the previous command. Consider the following example:
We start by looking for a word in a file
grep -i joe /some/long/directory/structure/user-lists/list-15
if joe is in that userlist, we want to remove him from it. We can either
fire up vi with that long directory tree as the argument, or as simply
as
vi !$
Which bash expands to:
vi /some/long/directory/structure/user-lists/list-15
A word of caution:
!$ expands to the end word of the previous command.
What's a word? The bash man page calls a word "A sequence of characters
considered as a single unit by the shell." If you haven't changed anything,
chances are good that a word is a quoted string or a white-space delimited
group of characters. What is a white-space delimited group of characters
? It's a group of characters that are separated from other characters
by some form of white-space (which could be a tab, space, etc.) If you're
in doubt, :p works here too.
Another thing to keep in
mind when using !$ is that if the previous command
had no agruments, !$ will expand to the previous command
rather than the most recent argument. This can be handy if, for example,
you forget to type vi and you just type the filename. A simple
vi !$ and you're in.
Similar to
!$ is !*. !* is all of
the arguments to the previous command rather than just the last one.
As usual, this is useful in many situations. Here's a simple example:
vi cd /stuff
oops!
[exit vi, twice]
!*
Which bash expands to: cd /stuff
... ... ...
A few handy movement commands
Sometimes a mistake is noticed
before the enter key is pressed. We've already talked about terminals
that don't translate cursor-keys properly, so how do you fix a mistake?
To make matters worse, sometimes the backspace key gets mapped to ^H
or even worse something like ^[[~. Now how do you fix your mistake before
hitting the enter key?
Once again, bash comes through
for us. Here are some of the movement keystrokes that I use most often:
- ^w erase word
- ^u erase from here to beginning
of the line (I use this ALL the time.)
- ^a move the cursor to the beginning
of the line
- ^e move the curor to the end of
the line
There are more of course,
but those are the ones you simply can't live without. For those who
don't know the ^N notation means ctrl+N, don't confuse it with hats
mentioned above.
tab-tab
One of my favorite features
of bash is tab-completion. Tab-completion works in a couple of ways,
it can complete filenames in the current directory or in your $PATH.
Like the !commands above, you just need to give bash
enough of the filename to make it unique and hit the tab key -- bash
will do the rest for you. Let's say you have a file in your home directory
called ransom.note, consider the following:
mor[tab] ran[tab]
Will expand to
more ransom.note
Let's say you also have
a file named random in your home directory. ran
above is no longer enough to be unique, but you're in luck. If you hit
tab twice, bash will print the list of matching files to the screen
so that you can see what you need to add to make your shortcut unique.
Send comments to Sam Rowe,
deadman at deadman dot org.
fc: Displays, Edits, and Reexecutes Commands
The fc (fix command) builtin enables you to display the history
list and edit and reexecute previous commands. It provides many
of the same capabilities as the command line editors.
When you call fc with the -l option, it displays
commands from the history list. Without any arguments, fc
-l lists the 16 most recent commands in a numbered list,
with the oldest appearing first:
$ fc -l
1024 cd
1025 view calendar
1026 vim letter.adams01
1027 aspell -c letter.adams01
1028 vim letter.adams01
1029 lpr letter.adams01
1030 cd ../memos
1031 ls
1032 rm *0405
1033 fc -l
1034 cd
1035 whereis aspell
1036 man aspell
1037 cd /usr/share/doc/*aspell*
1038 pwd
1039 ls
1040 ls man-html
The fc builtin can take zero, one, or two arguments with the
-l option. The arguments specify the part of the history
list to be displayed:
fc -l [ first [ last ]]
The fc builtin lists commands beginning with the most recent
event that matches first. The argument can be an event number, the
first few characters of the command line, or a negative number,
which is taken to be the n th previous command. If you provide
last , fc displays commands from the most recent event that
matches first through the most recent event that matches
last . The next command displays the history list from event
1030 through event 1035:
$ fc -l 1030 1035
1030 cd ../memos
1031 ls
1032 rm *0405
1033 fc -l
1034 cd
1035 whereis aspell
The following command lists the most recent event that begins
with view through the most recent command line that begins
with whereis:
$ fc -l view whereis
1025 view calendar
1026 vim letter.adams01
1027 aspell -c letter.adams01
1028 vim letter.adams01
1029 lpr letter.adams01
1030 cd ../memos
1031 ls
1032 rm *0405
1033 fc -l
1034 cd
1035 whereis aspell
To list a single command from the history list, use the same
identifier for the first and second arguments. The following command
lists event 1027:
$ fc -l 1027 1027
1027 aspell -c letter.adams01
You can use fc to edit and reexecute previous commands.
fc [-e editor ] [ first [ last ]]
When you call fc with the -e option followed
by the name of an editor, fc calls the editor with event(s) in the
Work buffer. Without first and last , fc defaults
to the most recent command. The next example invokes the vi(m) editor
to edit the most recent command:
$ fc -e vi
The fc builtin uses the stand-alone vi(m) editor. If you set
the FCEDIT variable, you do not need to use the
-e option to specify an editor on the command line.
Because the value of FCEDIT has been changed to /usr/bin/emacs
and fc has no arguments, the following command edits the most recent
command with the emacs editor:
$ export FCEDIT=/usr/bin/emacs
$ fc
If you call it with a single argument, fc invokes the editor
on the specified command. The following example starts the editor
with event 21 in the Work buffer. When you exit from the editor,
the shell executes the command:
$ fc 21
Again you can identify commands with numbers or by specifying
the first few characters of the command name. The following example
calls the editor to work on events from the most recent event that
begins with the letters vim through event 206:
$ fc vim 206
When you execute an fc command, the shell executes whatever you
leave in the editor buffer, possibly with unwanted results. If you
decide you do not want to execute a command, delete everything from
the buffer before you exit from the editor.
You can reexecute previous commands without going into an editor.
If you call fc with the -s option, it skips the editing
phase and reexecutes the command. The following example reexecutes
event 1029:
$ fc -s 1029
lpr letter.adams01
The next example reexecutes the previous command:
$ fc -s
When you reexecute a command you can tell fc to substitute one
string for another. The next example substitutes the string
john for the string adams in event 1029
and executes the modified event:
$ fc -s adams=john 1029
lpr letter.john01
Using an Exclamation Point (!) to Reference Events
The C Shell history mechanism uses an exclamation point to reference
events, and is available under bash. It is frequently more cumbersome
to use than fc but nevertheless has some useful features. For example,
the !! command reexecutes the previous event, and the
!$ token represents the last word on the previous command
line.
You can reference an event by using its absolute event number,
its relative event number, or the text it contains. All references
to events, called event designators, begin with an exclamation point
(!). One or more characters follow the exclamation
point to specify an event.
You can put history events anywhere on a command line. To escape
an exclamation point so that it is treated literally instead of
as the start of a history event, precede it with a backslash (\)
or enclose it within single quotation marks.
An event designator specifies a command in the history list.
Event designators
| Designator |
Meaning |
| ! |
Starts a history event unless followed immediately by
SPACE, NEWLINE, =, or (. |
| !! |
The previous command. |
| !n |
Command number n in the history list. |
| !-n |
The n th preceding command. |
| !string |
The most recent command line that started with
string . |
| !?string[?] |
The most recent command that contained string
. The last ? is optional. |
| !# |
The current command (as you have it typed so far). |
| !{event} |
The event is an event designator. The
braces isolate event from the surrounding
text. For example, !{-3}3 is the third most recently
executed command followed by a 3. |
You can always reexecute the previous event by giving a
!! command. In the following example, event 45 reexecutes
event 44:
44 $ ls -l text
-rw-rw-r-- 1 alex group 45 Apr 30 14:53 text
45 $ !!
ls -l text
-rw-rw-r-- 1 alex group 45 Apr 30 14:53 text
The !! command works whether or not your prompt
displays an event number. As this example shows, when you use the
history mechanism to reexecute an event, the shell displays the
command it is reexecuting.
A number following an exclamation point refers to an event. If
that event is in the history list, the shell executes it. Otherwise,
the shell displays an error message. A negative number following
an exclamation point references an event relative to the current
event. For example, the command !-3 refers to the third
preceding event. After you issue a command, the relative event number
of a given event changes (event -3 becomes event -4).
Both of the following commands reexecute event 44:
51 $ !44
ls -l text
-rw-rw-r-- 1 alex group 45 Nov 30 14:53 text
52 $ !-8
ls -l text
-rw-rw-r-- 1 alex group 45 Nov 30 14:53 text
When a string of text follows an exclamation point, the shell
searches for and executes the most recent event that began
with that string. If you enclose the string between question marks,
the shell executes the most recent event that contained that
string. The final question mark is optional if a RETURN would immediately
follow it.
68 $ history 10
59 ls -l text*
60 tail text5
61 cat text1 text5 > letter
62 vim letter
63 cat letter
64 cat memo
65 lpr memo
66 pine jenny
67 ls -l
68 history
69 $ !l
ls -l
...
70 $ !lpr
lpr memo
71 $ !?letter?
cat letter
...
Optional - Word Designators
A word designator specifies a word or series of words
from an event.
Word designators
| Designator |
Meaning |
| n |
The n th word. Word 0 is normally
the command name. |
| ^ |
The first word (after the command name). |
| $ |
The last word. |
| m - n |
All words from word number m through word
number n ; m defaults
to 0 if you omit it (0- n ). |
| n* |
All words from word number n through the
last word. |
| * |
All words except the command name. The same as 1*. |
| % |
The word matched by the most recent ?string?
search. |
The words are numbered starting with 0 (the first word on the
line -- usually the command), continuing with 1 (the first word
following the command), and going through n (the last
word on the line).
To specify a particular word from a previous event, follow the
event designator (such as !14) with a colon and the number
of the word in the previous event. For example, !14:3 specifies
the third word following the command from event 14. You can specify
the first word following the command (word number 1) by using a
caret (^) and the last word by using a dollar sign ($).
You can specify a range of words by separating two word designators
with a hyphen.
72 $ echo apple grape orange pear
apple grape orange pear
73 $ echo !72:2
echo grape
grape
74 $ echo !72:^
echo apple
apple
75 $ !72:0 !72:$
echo pear
pear
76 $ echo !72:2-4
echo grape orange pear
grape orange pear
77 $ !72:0-$
echo apple grape orange pear
apple grape orange pear
As the next example shows, !$ refers to the last word
of the previous event. You can use this shorthand to edit, for example,
a file you just displayed with cat:
$ cat report.718
...
$ vim !$
vim report.718
...
If an event contains a single command, the word numbers correspond
to the argument numbers. If an event contains more than one command,
this correspondence does not hold true for commands after the first.
In the following example, event 78 contains two commands separated
by a semicolon so that the shell executes them sequentially; the
semicolon is word number 5.
78 $ !72 ; echo helen jenny barbara
echo apple grape orange pear ; echo helen jenny barbara
apple grape orange pear
helen jenny barbara
79 $ echo !78:7
echo helen
helen
80 $ echo !78:4-7
echo pear ; echo helen
pear
helen
On occasion you may want to change an aspect of an event you
are reexecuting. Perhaps you entered a complex command line with
a typo or incorrect pathname, or you want to specify a different
argument. You can modify an event or a word of an event by putting
one or more modifiers after the word designator, or after
the event designator if there is no word designator. Each modifier
must be preceded by a colon (:).
The substitute modifier is more complex than the other
modifiers. The following example shows the substitute modifier correcting
a typo in the previous event:
$ car /home/jenny/memo.0507 /home/alex/letter.0507
bash: car: command not found
$ !!:s/car/cat
cat /home/jenny/memo.0507 /home/alex/letter.0507
...
The substitute modifier has the following syntax:
[g]s/ old _/ new _/
where old is the original string (not a regular
expression), and new is the string that replaces
old . The substitute modifier substitutes the
first occurrence of old with new . Placing
a g before the s (as in gs/old/new/)
causes a global substitution, replacing all occurrences of
old . The / is the delimiter in the examples,
but you can use any character that is not in either old
or new . The final delimiter is optional if a
RETURN would immediately follow it. As with the vim Substitute command,
the history mechanism replaces an ampersand (&) in
new with old . The shell replaces a null old
string (s//new/) with the previous old string or string
within a command that you searched for with ?string?.
An abbreviated form of the substitute modifier is quick substitution.
Use it to reexecute the most recent event while changing some of
the event text. The quick substitution character is the caret (^).
For example, the command
$ ^old^new^
produces the same results as
$ !!:s/old/new/
Thus substituting cat for car in the previous event
could have been entered as
$ ^car^cat
cat /home/jenny/memo.0507 /home/alex/letter.0507
...
You can omit the final caret if it would be followed immediately
by a RETURN. As with other command line substitutions, the shell
displays the command line as it appears after the substitution.
Modifiers (other than the substitute modifier) perform simple
edits on the part of the event that has been selected by the event
designator and the optional word designators. You can use multiple
modifiers, each preceded by a colon (:).
The following series of commands uses ls to list
the name of a file, repeats the command without executing it (p
modifier), and repeats the last command, removing the last part
of the pathname (h modifier), again without executing it:
$ ls /etc/sysconfig/harddisks
/etc/sysconfig/harddisks
$ !!:p
ls /etc/sysconfig/harddisks
$ !!:h:p
ls /etc/sysconfig
$
This table lists event modifiers other than the substitute modifier.
Modifiers
| Modifier |
Function |
| e (extension) |
Removes all but the filename extension |
| h (head) |
Removes the last part of a pathname |
| p (print-not) |
Displays the command, but does not execute it |
| q (quote) |
Quotes the substitution to prevent further substitutions
on it |
| r (root) |
Removes the filename extension |
| t (tail) |
Removes all elements of a pathname except the last |
| x |
Like q but quotes each word in the substitution
individually |
Date: Fri, 28 May 2004 13:55:36 +0000
2004-05-28, 14:12(+02), Gabkin:
[...]
> As for zsh, I'm a bash man! (but does zsh have an evolutionary history
> facility like this?)
Yes, and much more. Some customizations possible for history:
APPEND_HISTORY <D>
If this is set, zsh sessions will append their
history list to the
history file, rather than overwrite it. Thus, multiple
parallel
zsh sessions will all have their history lists
added to the
history file, in the order they are killed.
EXTENDED_HISTORY <C>
Save each command's beginning timestamp (in seconds
since the
epoch) and the duration (in seconds) to the history
file. The
format of this prefixed data is:
`:<BEGINNING TIME>:<ELAPSED SECONDS>:<COMMAND>'.
HIST_ALLOW_CLOBBER
Add `|' to output redirections in the history.
This allows history
references to clobber files even when CLOBBER is
unset.
HIST_BEEP <D>
Beep when an attempt is made to access a history
entry which isn't
there.
HIST_EXPIRE_DUPS_FIRST
If the internal history needs to be trimmed to
add the current
command line, setting this option will cause the
oldest history
event that has a duplicate to be lost before losing
a unique event
from the list. You should be sure to set the value
of HISTSIZE to
a larger number than SAVEHIST in order to give
you some room for
the duplicated events, otherwise this option will
behave just like
HIST_IGNORE_ALL_DUPS once the history fills up
with unique events.
HIST_FIND_NO_DUPS
When searching for history entries in the line
editor, do not
display duplicates of a line previously found,
even if the
duplicates are not contiguous.
HIST_IGNORE_ALL_DUPS
If a new command line being added to the history
list duplicates an
older one, the older command is removed from the
list (even if it
is not the previous event).
HIST_IGNORE_DUPS (-h)
Do not enter command lines into the history list
if they are
duplicates of the previous event.
HIST_IGNORE_SPACE (-g)
Remove command lines from the history list when
the first
character on the line is a space, or when one of
the expanded
aliases contains a leading space. Note that the
command lingers
in the internal history until the next command
is entered before
it vanishes, allowing you to briefly reuse or edit
the line. If
you want to make it vanish right away without entering
another
command, type a space and press return.
HIST_NO_FUNCTIONS
Remove function definitions from the history list.
Note that the
function lingers in the internal history until
the next command is
entered before it vanishes, allowing you to briefly
reuse or edit
the definition.
HIST_NO_STORE
Remove the history (fc -l) command from the history
list when
invoked. Note that the command lingers in the internal
history
until the next command is entered before it vanishes,
allowing you
to briefly reuse or edit the line.
HIST_REDUCE_BLANKS
Remove superfluous blanks from each command line
being added to
the history list.
HIST_SAVE_NO_DUPS
When writing out the history file, older commands
that duplicate
newer ones are omitted.
HIST_VERIFY
Whenever the user enters a line with history expansion,
don't
execute the line directly; instead, perform history
expansion and
reload the line into the editing buffer.
INC_APPEND_HISTORY
This options works like APPEND_HISTORY except that
new history
lines are added to the $HISTFILE incrementally
(as soon as they are
entered), rather than waiting until the shell is
killed. The file
is periodically trimmed to the number of lines
specified by
$SAVEHIST, but can exceed this value between trimmings.
SHARE_HISTORY <K>
This option both imports new commands from the
history file, and
also causes your typed commands to be appended
to the history file
(the latter is like specifying INC_APPEND_HISTORY).
The history
lines are also output with timestamps ala EXTENDED_HISTORY
(which
makes it easier to find the spot where we left
off reading the
file after it gets re-written).
By default, history movement commands visit
the imported lines as
well as the local lines, but you can toggle this
on and off with
the set-local-history zle binding. It is also possible
to create
a zle widget that will make some commands ignore
imported
commands, and some include them.
If you find that you want more control over
when commands get
imported, you may wish to turn SHARE_HISTORY off,
INC_APPEND_HISTORY on, and then manually import
commands whenever
you need them using `fc -RI'.
I have:
HISTFILE=~/.zsh-history.$ZSH_VERSION
HISTSIZE=500
SAVEHIST=50000
setopt HIST_IGNORE_ALL_DUPS HIST_REDUCE_BLANKS \
HIST_SAVE_NO_DUPS HIST_VERIFY INC_APPEND_HISTORY NO_BANG_HIST
--
Stephane
Bash provides two builtin commands that allow you to manipulate the history
list and history file.
-
fc
-
fc [-e ename] [-nlr] [first] [last]
fc -s [pat=rep] [command]
Fix Command. In the first form, a range of commands from first
to last is selected from the history list. Both first
and last may be specified as a string (to locate the most
recent command beginning with that string) or as a number (an index
into the history list, where a negative number is used as an offset
from the current command number). If last is not specified
it is set to first. If first is not specified
it is set to the previous command for editing and -16 for listing. If
the `-l' flag is given, the commands are listed on standard
output. The `-n' flag suppresses the command numbers when
listing. The `-r' flag reverses the order of the listing.
Otherwise, the editor given by ename is invoked on a file
containing those commands. If ename is not given, the value
of the following variable expansion is used: ${FCEDIT:-${EDITOR:-vi}}.
This says to use the value of the FCEDIT variable if set,
or the value of the EDITOR variable if that is set, or
vi if neither is set. When editing is complete, the edited
commands are echoed and executed. In the second form, command
is re-executed after each instance of pat in the selected
command is replaced by rep. A useful alias to use with the
fc command is r='fc -s', so that typing
`r cc' runs the last command beginning with cc
and typing `r' re-executes the last command (see section
Aliases).
-
history
-
history [-c] [n]
history [-anrw] [filename]
history -ps arg
Display the history list with line numbers. Lines prefixed with with
a `*' have been modified. An argument of n says
to list only the last n lines. Options, if supplied, have
the following meanings:
-
-w
-
Write out the current history to the history file.
-
-r
-
Read the current history file and append its contents to the history
list.
-
-a
-
Append the new history lines (history lines entered since the beginning
of the current Bash session) to the history file.
-
-n
-
Append the history lines not already read from the history file
to the current history list. These are lines appended to the history
file since the beginning of the current Bash session.
-
-c
-
Clear the history list. This may be combined with the other options
to replace the history list completely.
-
-s
-
The args are added to the end of the history list as
a single entry.
-
-p
-
Perform history substitution on the args and display
the result on the standard output, without storing the results in
the history list.
When the `-w', `-r', `-a', or
`-n' option is used, if filename is given, then
it is used as the history file. If not, then the value of the
HISTFILE variable is used.
vague memory
- If you really are uncertain of the history or if you know you
could be searching back through many similar commands for one of
particular interest, then you can use this more brute-force method.
- Type the following command to get a list of all related commands
with their history numbers:
history | grep -i "<search string>"
- Once you've found the command you want, you can execute it specifically
by its number using the following built-in history expansion command:
... ... ...
Here's an example that suppresses duplicate commands, the simple
invocation of ls without any arguments,
and the shell built-ins bg,
fg, and exit:
export HISTIGNORE="&:ls:[bf]g:exit"
The amount of commands stored in the history file is
dependent on the size of the file you allocate. By default
500 commands are stored, but you can tweak these values
by setting the following options in a startup file:
HISTSIZE = 1000
HISTFILE = ~/.bash_history
To print out the entire history file, you can use
the history command:
$ history | tail -10
522 gvim
523 vim .bashrc
524 vim .bash_profile
525 history
526 ls
527 echo $SHELL
528 echo $HISTFILE
529 echo $HISTSIZE
530 vim .bashrc
531 history | tail -10
$
The number in the left column is the history item
number. This can be bigger than the size of your stored
history file, as commands from the current shell are
not added to the file until the shell is closed.
You can jump straight to executing any line in your
history by typing an '!' followed by the item number.
So for example if we wanted to echo the shell name to
the console again we could write echo $SHELL
or simply:
$ !527
/bin/bash
$
Searching command history
You can also use the ! command to search through
the history, by replacing the item number with characters
from the start of the command. The previous example
can now just as easily be written:
$ !echo
echo $SHELL
/bin/bash
$
Often this becomes unwieldy since you have to match
the command from the beginning, and many commands start
in the same way (eg. "echo $HISTFILE", "echo $HISTSIZE",
"echo $SHELL"). You can always hack something together
using history and grep, but there's an easier way with
the '!?' command. '!?' followed by a simple string,
executes the last command in the history that contains
that string.
So, to reprint the name of the shell we could have
simply typed:
$ !? SHELL
/bin/bash
#
More usefully, you can interactively search the command
history at the console by hitting CTRL-R at the prompt
and typing the section of the string you are looking
for. You can only use CTRL-R interactively, that is,
not in a script (although relying on the history in
a script can be dangerous anyway), but it can save you
more keystrokes as it displays the match at each point,
meaning you can stop searching once you've found it.
O'Reilly ONLamp Blog
If you’re like me, you never want to lose a command.
I’m constantly searching back through them to find out
just what those command line flags were, what the esoteric
command is (and where it’s located), and most of all:
what in Tcl’s name did I do last month when I installed
foobazzulator. First thing to know:
control-r.
However, bash ships with a ridiculously short memory:
500 commands. That’s not enough: right now, my powerbook’s
iTerm prompt is:
[/Users/jwellons]
111280$
Go into your .bash_profile now and add
these lines, before you read on:
HISTFILESIZE=1000000000
HISTSIZE=1000000
Unless you’re very precocious, that should square you
away for about 10 years (I’m at about 22 months since
enlightenment).
Once you develop control-r as a fast way to
search your command history, you’ll notice immediate
stress relief, and as I do everyday, wish you’d done
this years before.
Now that you have commands piling up, you can do
more than just use them. You can analyze them too, for
fun and profit (since time = money)!
The basic starter is
cut -f1 -d" " .bash_history | sort | uniq -c | sort
-nr | head -n 30
In other words, just what do you spend so much time
typing? Here’s the money: Anything in at least the top
ten, assuming it is not from somHistory can be browsed
using arrow commands, but more efficient way is to use
Ctrl-R for anything but previous half-dozen of commands.
Ctrl-R mechanism provides search in history: typed characters
can be in any place of the command will autocomplete
as soon as there’s a match to a history entry, then
you just need to hit enter to reexecute the command
-time splurge, needs to be aliased to a one or two letter
shorthand.
My top command is v for vim,
which I’ve executed 9225 times. If those two extra letters,
which require me to switch hands, then use adjacent
fingers take an extra half-second each time: that’s
well over an hour wasted! And what a terribly drudgerous
and unhealthy hour it is too: mindlessly typing
im 9225 times!
Even worse, who knows how desperately I needed to
open that file, and yet I needed to type superfluous
characters, probably messing them up on the first three
tries.
Actually, that’s only my second highest command.
cl tops the list at 11116. You see, last
time I did this analysis, I noticed I was spending (yes,
spent, like lines of code, there is no glory
in using a lot of them) many commands first cd‘ing
to a directory, then listing the contents. Here’s
cl:
# Compress the cd, ls -l series of commands.
alias lc="cl"
function cl () {
if [ $# = 0 ]; then
cd && ll
else
cd "$*" && ll
fi
}
There you have it, accompanied by its most common typo.
Add this to your bash profile now, and you’ll add several
hours to your life. Hurry! Don’t wait! It may not seem
like much now, but no one lies on her deathbed wishing
she had spent more time first changing directories,
waiting for it to return, then typing ls.
Since I know you’re dying to see the rest, here’s
my whole thirty, unaliased for readability:
11116 cl
9225 vim
7833 ll The alias of ll depends
on the OS I’m on, but for my Mac, it’s ls -AGlFT.
5145 cd
4858 clear
4563 rm
3950 alias to log into the master db server
at my old workplace
3740 lt version of ll that puts
most recently modified stuff at the bottom. Mandatory!
Add -tr to ll above
3435 mod a function that does lt,
but runs it through tail
3236 mv
2103 ls
1887 grep
1863 perl
1834 df
1767 mzscheme
1679 alias to log into my personal server
1580 g++
1544 cat
1186 scp
1080 find
988 man
925 echo
921 mkdir
907 sudo
888 history
841 alias to log into the dev server at my
old workplace
831 cp
763 gpg
758 locate
733 gzip
Depending on response, we may do another section
with pie charts, finding all the typo permutations for
simple commands (there’s a lot), and searching for common
sequences.
What I really want to see, though, is your top commands.
April, 2006 (samag.com) When used as an audit utility, shell history
has serious drawbacks. For example:
- Once a shell history file contains the maximum number of commands,
old commands are removed as new ones are entered.
- History files may be modified by a user who is trying to cover
his tracks.
Timestamps are not available to determine when a command was executed.
- History files are typically stored in the user's home directories
making it difficult to process the information.
- It can be tricky to tell who executed certain commands if someone
used su to become another user, such as root.
09.27.2006 | Techtarget.com
The Bash shell is the default shell environment in most Linux distributions,
including all flavours of Red Hat. One default feature of the Bash shell
is to record a history of all the commands entered by a user in a log
file called .bash_history, found in the user's home directory.
The history in this file can be retrieved from the command line using
the more or cat binaries or by using the internal
Bash command, history. For many users, it is useful to
retrieve the previously executed commands, usually to save the effort
of re-typing them.
So why might we want to limit or disable this Bash command history?
Well, among the commands that your users type are file names, command
names, IP addresses, passwords and a myriad of other data that are potentially
valuable to an attacker intent on subverting or compromising your host.
Keeping a record of this data means an attacker may only need to compromise
an individual .bash_history file rather than a more difficult source
of data.
To limit the size and behaviour of the .bash_history file, you need
to edit the behavior of the shell in the /etc/profile file (the central
version of the .bash_profile file usually contained in users home directories).
Add or change the following three lines to the file:
export HISTSIZE=100
export HISTFILESIZE=100
unset HISTFILE
The first two lines set the length and size of the history stored
in the file. The last line unsets the HISTFILE variable that tells the
Bash shell not to save history when the user logs out of the interactive
session. This means an online user will only be able to see the history
of the last 100 commands, and that history will disappear after the
user logs out of the host.
A further way to ensure the command history is removed is to include
a command in the .bash_logout file (other shells use the .logout file).
The contents of the .bash_logout file are executed when the user logs
out. You can see a simple .bash_logout file on the following lines:
# ~/.bash_logout
/bin/rm -f $HOME/.bash_history
clear
The rm command will remove the .bash_history file from the users
home directory when the user logs out. To add this to the file you can
edit the .bash_logout file contained in the /etc/skel directory (the
contents of this directory are copied to the home directories of all
new users when they are created). Existing users will need the .bash_logout
files in their home directories adjusted to add the command.
There is, however, one gotcha associated with this change, and that
is that if an attacker has compromised your host, then the history of
their actions might not be recorded. Of course, any talented attacker
will use other means (including this exact method and others like the
deletion or editing of log files) to remove that history.
Word designators are used to select desired words from the event.
A `:' separates the event specification from the word designator.
It may be omitted if the word designator begins with a `^',
`$', `*', `-', or `%'.
Words are numbered from the beginning of the line, with the first word
being denoted by 0 (zero). Words are inserted into the current line
separated by single spaces.
For example,
-
!!
-
designates the preceding command. When you type this, the preceding
command is repeated in toto.
-
!!:$
-
designates the last argument of the preceding command. This may
be shortened to
!$.
-
!fi:2
-
designates the second argument of the most recent command starting
with the letters
fi.
Here are the word designators:
-
0 (zero)
-
The
0th word. For many applications, this is the command
word.
-
n
-
The nth word.
-
^
-
The first argument; that is, word 1.
-
$
-
The last argument.
-
%
-
The word matched by the most recent `?string?'
search.
-
x-y
-
A range of words; `-y' abbreviates
`0-y'.
-
*
-
All of the words, except the
0th. This is a synonym
for `1-$'. It is not an error to use `*'
if there is just one word in the event; the empty string is returned
in that case.
-
x*
-
Abbreviates `x-$'
-
x-
-
Abbreviates `x-$' like `x*',
but omits the last word.
If a word designator is supplied without an event specification,
the previous command is used as the event.
-
accept-line (Newline or Return)
-
Accept the line regardless of where the cursor is. If this line
is non-empty, add it to the history list according to the setting
of the
HISTCONTROL and HISTIGNORE variables.
If this line is a modified history line, then restore the history
line to its original state.
-
previous-history (C-p)
-
Move `back' through the history list, fetching the previous command.
-
next-history (C-n)
-
Move `forward' through the history list, fetching the next command.
-
beginning-of-history (M-<)
-
Move to the first line in the history.
-
end-of-history (M->)
-
Move to the end of the input history, i.e., the line currently being
entered.
-
reverse-search-history (C-r)
-
Search backward starting at the current line and moving `up' through
the history as necessary. This is an incremental search.
-
forward-search-history (C-s)
-
Search forward starting at the current line and moving `down' through
the the history as necessary. This is an incremental search.
-
non-incremental-reverse-search-history (M-p)
-
Search backward starting at the current line and moving `up' through
the history as necessary using a non-incremental search for a string
supplied by the user.
-
non-incremental-forward-search-history (M-n)
-
Search forward starting at the current line and moving `down' through
the the history as necessary using a non-incremental search for
a string supplied by the user.
-
history-search-forward ()
-
Search forward through the history for the string of characters
between the start of the current line and the point. This is a non-incremental
search. By default, this command is unbound.
-
history-search-backward ()
-
Search backward through the history for the string of characters
between the start of the current line and the point. This is a non-incremental
search. By default, this command is unbound.
-
yank-nth-arg (M-C-y)
-
Insert the first argument to the previous command (usually the second
word on the previous line) at point. With an argument n,
insert the nth word from the previous command (the words
in the previous command begin with word 0). A negative argument
inserts the nth word from the end of the previous command.
-
yank-last-arg (M-. or M-_)
-
Insert last argument to the previous command (the last word of the
previous history entry). With an argument, behave exactly like
yank-nth-arg. Successive calls to yank-last-arg
move back through the history list, inserting the last argument
of each line in turn.
Entering the
history command
without any switches displays the history list with line numbers. If
that's too much information, enter history
N where N is the number of previously
executed commands you want displayed.
Bash also allows for incremental
search on the history list. Use ctrl+r
for a backward/reverse search or ctrl+s
to perform a forward search. As you type the first few letters of the
command, the last command from the history list that matches with your
string would be displayed.
Since you are at the command line,
you can club combine some popular commands and cook up interesting surprises.
One such example is to pass history
through grep
along with the first few letters of a command. For example, try this
simple hack, which displays all the commands beginning with the letters
you supply:
history | grep -i first-few-letters-of-command
History expansion
History expansion serves two purposes,
the first is repeating a command from the history list. The second is
selecting portions from a command for substituting into the current
command.
History expansions are implemented by
the history expansion character '!'. The line selected from the history
list is called 'event' and portions of that command that are selected
are called 'words'. Depending on your needs, you can either use 'word'
or 'event designators'.
Event designators
Event designators, invoked by the
history expansion character are used for command substitution, that
is, repeating a command from the list.
! starts history
substitution. It can be escaped with a backslash (\), since it is a
special character. In this example, history command 1008 -- a simple
ls
-- is repeated:
!1008
ls
animate
Desktop
DOWNLOADS
evolution
songs
sonu_result.png
star trek
Another useful event designator
is !string,
which runs the most recent command beginning with the string you specify.
Word designators
Word designators are used to select specified
words from an event. A colon (:) is used to separate word designators
from events. Words in a command are numbered from the beginning of the
line, with the first word denoted by zero (0). Once selected, a word
is inserted into the current command separated by a single space.
Some common word designators are
n,
which refers to the nth word;
^ refers to the
first word; $
refers to the last word and *
refers to the complete line entry except for the first word, which is
the command.
For example,
!conv:5 displays
the fifth word from the last command beginning with
!conv, while
!conv:$
would display the last word from the same command. Please note that
!conv:*
is same as !conv:1-$
- both resulting in the complete command except for the first word.
Modifying selected words
There are a number of modifiers
that help you to describe how you want the selections to behave. Each
modifier in a command needs to be preceeded with a colon (:) and you
can use more than one modifier in a command. A very popular modifier
is p
which results in the command being listed instead of being executed.
For example:
!l:p
ls -l
There is also a search-and-replace
type modifier that you can use when you wish to replace some text with
some other. This modifier is s/old/new.
For example:
!!:s/-l/-a/
ls -a
[...]
Note: A !! is used to refer to the last command in the history list. The last command was ls -l and so the -l was replaced with -a and the new command, ls -a was executed.
Conclusion
After encountering a thread in a popular
forum board that just brushed on Bash and its event designators, I've
since done enough reading from the man pages and the web to officially
declare that it is a very cool feature which requires very little effort
to get hooked on.
The usage of the bash-history feature
could be as fun as helpful, also it can save a lot of time if you are
one of those who use bash-terminals for everything (if you are not,
what the hell are you doing here with Linux Mr. Green ...just kidding
Wink )
I'm not going to talk in extent about the usage of bash-history, I only
want to show you a couple of tips. If you want to learn more about it
you can take a look to the chapter 7 of the Bash Reference Manual
(such as ramfree "pointed" long time ago, should be under every linux
user's pillow Wink )
Here are the tips:
$ !n --Will execute the line n of the history record.
$ !-n --Will execute the command n lines back.
$ !! --Will execute the last command. As !-1 or "up-arrow + return"
$ !string --Will execute the most recent command starting with
the given string. In my experience string is just the first characters
of the first word of the command, so don't use space characters.
$ !?string[?] --Will execute the most recent command containing
the given string. The last "?" may be omitted if the string is followed
by a new line. So if the string includes space characters or similar
close it with "?". This can be used to avoid the error that appears
with !string when used with long strings.
$ ^string1^string2 --String2 will substitute string1 on the last
command. Cool, isn't it? This is equivalent to !!:s/string1/string2/
which is cooler Wink Any one feels a bit like in vi?
$HISTIGNORE or
How-To improve the history usage:
You might want to set up the shell variable $HISTIGNORE to avoid having
consecutive duplicate commands or unuseful commands appended to the
history list. So you'll get rid of the never ending story of hitting
the up arrow trough simple and repetitive commands.
Here is an example of usage:
export HISTIGNORE="&:l[sl]:[fb]g:exit"
Setting this way the $HISTIGNORE, the consecutive duplicated commands,
the simple calls to ls, ll, fg and bg commands without arguments, and
calls to the exit command will not be appended to the history list,
so navigate though it will be much easier.
# BASH HISTORY SEARCH AND REPLACE
^string1^string2^ Quick substitution. Repeat the last command, replacing string1 with
string2. Equivalent to ``!!:s/string1/string2/''
# MORE BASH COMMAND LINE TRICKERY (messing with the history)
make a directory then move into it:
mkdir cgi-bin; cd !#$
!#$ is shorthand for "the first word of this command". If I wanted to pick the third word
out of the previous command, that would be: !!:3 (don't forget there is a zeroth word).
# execute the most recent command the contains the following string:
!?string
# globally search replace on the previous line:
!!:gs/old/new/
# HEADS AND TAILS
ever wanted to copy a few files in the same directory, all of which have same
long prefix, like: cp /usr/local/etc/apache/file1.txt /usr/local/etc/apache/file2.txt
you can grap and reuse that prefix. It's named !#:1:h like:
cp /usr/local/etc/apache/file1.txt !#:1:h/file2.txt !#:1:h/file3.txt
# SAVING A COMMAND WITHOUT EXECUTING
While using bash, if you have typed a long command, and then realize you don't want to execute it yet, don't delete it. Simply
append a # to the beginning of the line, and then hit enter. Bash will not execute the command, but will store it in history so later
you can go back, remove the # from the front, and execute it.
# GOING FORWARD A BACK A WORD
META-F goes forward a word
META-B goes backward a word
# COMPARE A FILE WITH IT'S VARIOUS VERSIONS IN THE SAME DIRECTORY
diff file.*
# EXAMPLE of a basic command line script
% for f in `ls | grep -v ".sh"`; { mv ${f} ${f}.sh }
# searching the history
Cntrl-R starts a reverse incremental search
# Keyboard shortcuts:
CTRL-k: delete ('kill') from cursor position to the end of the line
* CTRL-u: delete from cursor position to the beginning of the line
* ALT-d: delete from cursor position to the end of the current 'word'
* CTRL-w: delete from cursor position to the beginning of the current 'word'
* CTRL-a: move cursor to the first character of the line
* CTRL-e: move cursor beyond the last character of the line
* ALT-a: move cursor to the first character of the current 'word'
* ALT-e: move cursor to the last character of the current 'word'
* CTRL-y: insert latest deleted 'word'
* ESC-_ or !$: repeats the last argument of the previous command.
Example: You created a directory with mkdir /usr/local/bin/peter/pan. Now you want to change into that directory with cd. Instead of typing the path again, you type cd ESC-_ or
# Diff 2 files with a common base:
diff {alpha,beta}site/config/Config.pl
gh -
grep history
#!/bin/bash
#
# gh - grep history
#
# A simple script for the forgetful and lazy (I use it all the time).
#
# This script allows you to re-use bash history commands...
#
# A: ...if you can't remember the whole command or path...
# B: ...if you don't feel like pressing the "up" arrow for 2 minutes...
# C: ...if you are too forgetful or lazy to type "grep <search-string> ~/.bash_history"!
#
# -Mike Putnam http://www.theputnams.net
#
# Usage: gh <search-string>
#
grep $1 ~/.bash_history
exit 0
On Sat, 5 May 2001, Joost van der Lugt
wrote:
Hi all,
I've been looking into this for a litle bit and am unable to find
an
answer. This is a feature AFAIK only implemented by SuSE:
At a prompt type one or more characters then use Page Up/Page Down
to scroll through all commands that started with these characters.
So typing:
cd
would then give a 'scrollable' list of anything that started with
cd
simply hit enter when you reach the command you were looking for.
I know Ctrl-r and am familiar with ! but they are not as nice, and
really not the same.
Would anybody have a clue as to how this could be implemented?
I don't think it is shell dependent, so I don't think it's a bash
option but I could very well be wrong.
(Tried the dotfile generator, but don't see anything there)
The option is _really_ addictive therefore my post:)
Thanks,
--
Cheers,
Joost van der Lugt
--
To UNSUBSCRIBE, email to debian-user-request@lists.debian.org
with a subject of "unsubscribe". Trouble? Contact listmaster@lists.debian.org>
In case of broken links
please try to use Google search. If you find the page please notify
us about new location
A history substitution begins with a
!, and may occur anywhere on the command line. The power of history
substitution is impressive. There are too many ways of using it to explain
here, but complete details can be found in the csh man page. Some of
the simpler forms are:
!! Refer to the previous command
!n Refer to command-line n
!-n Refer to the current command-line minus n.
!str Refer to the most recent command starting with str.
!?str Refer to the most recent command containing str.
You can also refer to individual words
of a previous command. If necessary, you can separate the event specification
(above) from the word specification.
!!:0 The first word of the previous command line
!!:n The nth argument of the previous command
!!:$ The last argument of the previous command
!!:* All of the arguments of the previous command
Further modification to the commands
can be done including editing particular words, but we won't go into
further detail here. Suffice it to say that there's probably a way to
do whatever it is you are trying to accomplish with history substitution.
Quick substitution can be done, if all
you want to do is change a single string from the previous command.
For instance, if you just sent mail to dela with "mail dela", and now
want to send mail to kaser, you can say
^dela^kaser^
and the string "dela" will be replaced
with "kaser".
bash stores the commands you type and provides access to them through
its history mechanism. This makes it possible to repeat a previous
command, include portions of a previous command in the current command
or re-execute a previous command after fixing a typing error.
The list of all commands currently saved by the history mechanism
is displayed by executing the history command. The
history commands numbers the old commands it displays.
Typing
!n
will re-execute the command numbered n.
If you would rather not lookup the number of a previous command,
you can type ! followed by the first characters of the
command. For example,
!ls
will execute the last command that began with ls.
Another way to avoid looking up the number is to use control-p.
Pressing control-p will display your previous command,
which you can then edit. Repeatedly pressing control-p
will go back to earlier commands.
If the command you want to execute is similar to a previous command,
or you want to fix a typing mistake, you can control-p
back to the command, then edit it using control-b or the
left arrow key to move the cursor back a character, contol-f
or the right arrow key to move forward a character, control-a
to move to the beginning of a line, control-e to move to
the end of a line, and control-d to delete a character.
Backspace and Delete work as usual. Anything
you type is inserted where the cursor is located.
Another useful function the history mechanism provides is the ability
to re-use the arguments of the previous command. The characters
!* occurring in a command are replaced by the arguments
to the previous command. Thus, one can first check the contents of a
file by typing
less somelongfilename
and then print the file by typing
lp !*
You can avoid typing somelongfilename by just typing enough of it
so that the shell can recognize it, (for example ``somel'' for the filename
``somelongfilename'') and pressing tab. bash will type
the rest of the filename for you. If there is another file of a similar
name, such as ``somelongfile2'', and you use tab to complete the name,
bash will type the beginning of the two filenames until it encounters
a discrepancy. In this case, it would type ``somelongfile''. Then it
will beep and wait for you to finish typing in the filename of your
choice.
Finally, you can fix simple typing mistakes in a command by typing
^old-string^new-string
This causes the shell to re-execute the last command after first replacing
the first occurrence of old-string by new-string.
History expansion is similar to csh ’s. It is
enabled by default in interactive shells. History expansion
happens before the shell breaks the input into words,
although quoting is recognized and quoted text is
treated as one history ‘‘word’’. History substitution
is performed on history events
, which consist of an event designator (which previous
line to start with), a word designator (which word from that
line to use, starting with zero), and one or more optional modifiers
(which parts of the words to use).
Colons separate the three parts, although the colon
between the event designator and word designator may be omitted when
the word designator begins with ˆ , $ , * ,
− , or % . Each modifier is separated from the nextone with
a colon. The histchars variable specifies the start-of-history
and quick substitution characters, and also the comment character that
indicates that the rest of a line is a comment. The previous command
is the default event if no event designator is supplied.
The event designators are:
start a history substitution
!
n -- command line n
!−
n -- current line minus n (
n previous)
!! --
the previous command
!
str -- most recent command line starting
withstr
!?
str [ ? ] -- most recent command
line containing str
!# --
the entire command line typed so
far
ˆ
old ˆ new ˆ quick
substitution: repeat last command
changing old to new
The word designators are:
0 the zero’th word (command name)
n word n
ˆ the first argument, i.e., word one
$ the last argument
% the word matched by the most recent
!? str ? search
x − y words x through
y . −y is short for 0−y
* words 1 through the last (like 1−$
)
n * words n through the last (like
n −$ )
n −words n through the next to
last
The modifiers are:
remove all but the suffix of a filename
g
make changes globally, use with s modifier,
below
h
remove the last part of a filename, leaving
the ‘‘head’’
p
print the command but do not execute it
q
quote the generated text
r
remove the last suffix of a filename
s/
old / new / substitute
new for old in the text. Any delimiter may be used.
An & in the replacement means the value of old. With
empty old , use last old , or the most recent !?
str ? search if there was no previous old
t
remove all but the last part of a filename,leaving
the ‘‘tail’’
x
quote the generated text, but break into words
at blanks and newline
& repeat the last substitution
Bash provides two builtin commands that allow you to manipulate the history
list and history file.
-
fc
-
fc [-e ename] [-nlr] [first] [last]
fc -s [pat=rep] [command]
Fix Command. In the first form, a range of commands from first
to last is selected from the history list. Both first
and last may be specified as a string (to locate the most
recent command beginning with that string) or as a number (an index
into the history list, where a negative number is used as an offset
from the current command number). If last is not specified
it is set to first. If first is not specified
it is set to the previous command for editing and -16 for listing. If
the `-l' flag is given, the commands are listed on standard
output. The `-n' flag suppresses the command numbers when
listing. The `-r' flag reverses the order of the listing.
Otherwise, the editor given by ename is invoked on a file
containing those commands. If ename is not given, the value
of the following variable expansion is used: ${FCEDIT:-${EDITOR:-vi}}.
This says to use the value of the FCEDIT variable if set,
or the value of the EDITOR variable if that is set, or
vi if neither is set. When editing is complete, the edited
commands are echoed and executed. In the second form, command
is re-executed after each instance of pat in the selected
command is replaced by rep. A useful alias to use with the
fc command is r='fc -s', so that typing
`r cc' runs the last command beginning with cc
and typing `r' re-executes the last command (see section
Aliases).
-
history
-
history [-c] [n]
history [-anrw] [filename]
history -ps arg
Display the history list with line numbers. Lines prefixed with with
a `*' have been modified. An argument of n says
to list only the last n lines. Options, if supplied, have
the following meanings:
-
-w
-
Write out the current history to the history file.
-
-r
-
Read the current history file and append its contents to the history
list.
-
-a
-
Append the new history lines (history lines entered since the beginning
of the current Bash session) to the history file.
-
-n
-
Append the history lines not already read from the history file
to the current history list. These are lines appended to the history
file since the beginning of the current Bash session.
-
-c
-
Clear the history list. This may be combined with the other options
to replace the history list completely.
-
-s
-
The args are added to the end of the history list as
a single entry.
-
-p
-
Perform history substitution on the args and display
the result on the standard output, without storing the results in
the history list.
When the `-w', `-r', `-a', or
`-n' option is used, if filename is given, then
it is used as the history file. If not, then the value of the
HISTFILE variable is used.
Word designators are used to select desired words from the event.
A `:' separates the event specification from the word designator.
It may be omitted if the word designator begins with a `^',
`$', `*', `-', or `%'.
Words are numbered from the beginning of the line, with the first word
being denoted by 0 (zero). Words are inserted into the current line
separated by single spaces.
For example,
-
!!
-
designates the preceding command. When you type this, the preceding
command is repeated in toto.
-
!!:$
-
designates the last argument of the preceding command. This may
be shortened to
!$.
-
!fi:2
-
designates the second argument of the most recent command starting
with the letters
fi.
Here are the word designators:
-
0 (zero)
-
The
0th word. For many applications, this is the command
word.
-
n
-
The nth word.
-
^
-
The first argument; that is, word 1.
-
$
-
The last argument.
-
%
-
The word matched by the most recent `?string?'
search.
-
x-y
-
A range of words; `-y' abbreviates
`0-y'.
-
*
-
All of the words, except the
0th. This is a synonym
for `1-$'. It is not an error to use `*'
if there is just one word in the event; the empty string is returned
in that case.
-
x*
-
Abbreviates `x-$'
-
x-
-
Abbreviates `x-$' like `x*',
but omits the last word.
If a word designator is supplied without an event specification,
the previous command is used as the event.
-
accept-line (Newline or Return)
-
Accept the line regardless of where the cursor is. If this line
is non-empty, add it to the history list according to the setting
of the
HISTCONTROL and HISTIGNORE variables.
If this line is a modified history line, then restore the history
line to its original state.
-
previous-history (C-p)
-
Move `back' through the history list, fetching the previous command.
-
next-history (C-n)
-
Move `forward' through the history list, fetching the next command.
-
beginning-of-history (M-<)
-
Move to the first line in the history.
-
end-of-history (M->)
-
Move to the end of the input history, i.e., the line currently being
entered.
-
reverse-search-history (C-r)
-
Search backward starting at the current line and moving `up' through
the history as necessary. This is an incremental search.
-
forward-search-history (C-s)
-
Search forward starting at the current line and moving `down' through
the the history as necessary. This is an incremental search.
-
non-incremental-reverse-search-history (M-p)
-
Search backward starting at the current line and moving `up' through
the history as necessary using a non-incremental search for a string
supplied by the user.
-
non-incremental-forward-search-history (M-n)
-
Search forward starting at the current line and moving `down' through
the the history as necessary using a non-incremental search for
a string supplied by the user.
-
history-search-forward ()
-
Search forward through the history for the string of characters
between the start of the current line and the point. This is a non-incremental
search. By default, this command is unbound.
-
history-search-backward ()
-
Search backward through the history for the string of characters
between the start of the current line and the point. This is a non-incremental
search. By default, this command is unbound.
-
yank-nth-arg (M-C-y)
-
Insert the first argument to the previous command (usually the second
word on the previous line) at point. With an argument n,
insert the nth word from the previous command (the words
in the previous command begin with word 0). A negative argument
inserts the nth word from the end of the previous command.
-
yank-last-arg (M-. or M-_)
-
Insert last argument to the previous command (the last word of the
previous history entry). With an argument, behave exactly like
yank-nth-arg. Successive calls to yank-last-arg
move back through the history list, inserting the last argument
of each line in turn.
HISTCONTROL
HISTCONTROL
A value of 'ignorespace' means to not enter lines which begin
with a space or tab into the history list. A value of 'ignoredups'
means to not enter lines which match the last entered line. A value of
'ignoreboth' combines the two options. Unset, or set to any
other value than those above, means to save all lines on the history list.
The second and subsequent lines of a multi-line compound command are not
tested, and are added to the history regardless of the value of HISTCONTROL.
If the list of values includes ignorespace, lines which begin with
a space character are not saved in the history list. A value of ignoredups
causes lines matching the previous history entry to not be saved. A value
of ignoreboth is shorthand for ignorespace and ignoredups. A value of erasedups
causes all previous lines matching the current line to be removed from the
history list before that line is saved. Any value not in the above list
is ignored. If HISTCONTROL is unset, or does not include a valid value,
all lines read by the shell parser are saved on the history list, subject
to the value of HISTIGNORE. The second and subsequent lines of a multi-line
compound
command are not tested, and are added to the history regardless of the value
of HISTCONTROL.
In bash 3.0 HISTCONTROL can be set to `erasedups' option, which causes
all lines matching a line being added to be removed from the history
list.
export HISTCONTROL=erasedups
HISTIGNORE
A colon-separated list of patterns used to decide which command lines should
be saved on the history list. Each pattern is anchored at the beginning
of the line and must match the complete line (no implicit '*'
is appended). Each pattern is tested against the line after the checks specified
by HISTCONTROL are applied. In addition to the normal shell
pattern matching characters, '&' matches the previous history
line. '&' may be escaped using a backslash; the backslash is
removed before attempting a match. The second and subsequent lines of a
multi-line compound command are not tested, and are added to the history
regardless of the value of HISTIGNORE. HISTIGNORE
subsumes the function of HISTCONTROL. A pattern of '&'
is identical to ignoredups, and a pattern of '[ ]*'
is identical to ignorespace. Combining these two patterns,
separating them with a colon, provides the functionality of ignoreboth.
You might want also to set up the shell variable HISTIGNORE to avoid
useless command littering you history. Natural candidates are cd -, all
variants of ls without argument, ll, etc.
export HISTIGNORE="&:l[sl]:[fb]g:cd \-"
Setting this way the $HISTIGNORE, the consecutive duplicated commands, the
simple calls to ls, ll, fg and bg commands without arguments, and calls
to the exit command will not be appended to the history list, so navigate
though it will be much easier.
An event designator references a command line stored in the history file.
There are several formats of event designators, they are as follows.
| ! |
Start a history substitution command, except when followed by
a space, tab, new-line, =, or (. |
| !! |
Reference the previous command line. Typing !! and pressing
Return executes the previous command. |
| !n |
Reference command line with event number n from the history
file. This references a specific event number. For example, if the
current event number is 7, you can specify an event number from
1 to 6. The command !3 would reexecute event 3, vi wsr.092989. |
| !-n |
Reference the nth previous command event. The current
event number -n. For example, if the current event number
is 7 and you type !-3, event number 4 is executed. |
| !str |
Reference the most recent command line starting with string
str. For example, !vi reexecutes the "vi apiprog.c"
command. |
| !?str[?] |
Reference the most recent command line containing the string
str. For example, !?dly reexecutes the "find ..."
command. |
| !{str} |
Insulate a reference string from adjacent characters. |
Word designators provide a way to reference specific arguments (words)
from a command line stored in the history file. A colon (:) separates the
event designator and the word designator. If the word designator begins
with $, %, ^, *, or - the : is not needed. If you want the word to be selected
from the previous command line, the second ! is not required. For example,
!!:2 and !:2 both refer to the second word on the previous
command. Words are zero relative, that is, word zero is the command itself.
The first argument (arg1) on the command line is word 1.
The available word designators are as follows:
- # -- The entire command line.
- 0 -- The first word on the command line, argument 0, which is
the command itself. For example, !2:0 refers to the word
"write" in the previous history listing.
- $ -- The last argument on the command line. For example,
!4:$ refers to the word "-print".
- % -- The word matched by the most recent ?s event designator.
- ^ -- The first argument (second word) on the command line. For
example, !4:^ refers to "/usr/local" on the "find ..." command
line.
- n -- The nth (nth + 1 word) on the command
line.
- * All arguments on the command line. Does not include word 0.
This is the same as 1-$.
- x-y -- A range of words starting at word x and
continuing through word y.
- x* -- An abbreviated form of x-$, which refers
to word x through the last word.
- x- -- The same as x* except the last word is not
included.
- -y -- Same as the range 0-y.
Modifiers
You can add modifiers after the word designators. A modifier is used
to modify the referenced command line. Each modifier must be preceded with
a colon (:).
- & -- Repeat the previous substitution(s/old/new/).
- e - Remove everything but the suffix.
- g - Globally apply the change to the first occurrence of a match
in each word. The g must precede other modifiers.
- h - Remove the last filename or directory name from the path.
Same as performing a dirname on the designated word.
- p - Print (display) the command but do not execute it.
- q - Quote the substituted words, preventing further substitutions.
- r - Remove a suffix of the form ".xxx," leaving the basename.
- s/old/new/ - Substitute the new string
in place of old string.
- t - Remove all leading pathname components, leaving the basename.
- x - Same as q, except words are delimited by spaces, tabs, and
new-lines.
The following examples illustrate how to use the Event Designators, Word
Designators, and the Modifiers.
- history -- List out the history events.
- !10 -- Execute history event number 10.
- !{l};.c -- Search for first event beginning with l and add .c
to the end of the command line.
- !vi -- Execute the last command that started with vi.
- ^bni^bin -- Substitute "bni" in the previous command line to
"bin."
- !vi:s/1.c/2.c/ -- Substitute "1.c" to "2.c" on the last command
that started with vi.
- !! Repeat the previous command history
- !2 -- Repeat the second command more mbox
- !v -- Repeat the last command which began with a vi vi letter.to.fred
- !-2 -- Repeat the command one previous to the last lc
- !??s -- Repeat the last command with the pattern third letter
s
- !! > file2 -- Produces a file consisting
of the last command
- !! | more -- Repeat the last command piped through more history
| more
- !5:0 file4 -- cat file4
- vi !5:2 -- vi file2
- vi !5$ -- vi file3
- more !5:2-$ -- more file2 file3
- !5^ file1 -- (this would produce an error since file1
is not executable).
Archiving Korn Shell History Files
Maybe you want to keep your shell history around for forensic analysis...
When used as an audit utility, shell
history has serious drawbacks. For example:
- Once a shell history file contains the maximum number of commands,
old commands are removed as new ones are entered.
- History files may be modified by a user who is trying to cover
his tracks.
Timestamps are not available to determine when a command was executed.
- History files are typically stored in the user's home directories
making it difficult to process the information.
- It can be tricky to tell who executed certain commands if someone
used su to become another user, such as root.
Copyright © 1996-2009 by Dr. Nikolai Bezroukov.
www.softpanorama.org was
created as a service to the UN Sustainable Development Networking Programme (SDNP)
in the author free time.
Submit
comments This document is an industrial compilation designed and created
exclusively for educational use and is placed under the copyright of the
Open Content License(OPL).
Site uses AdSense so you need to be aware of Google privacy policy. Original materials copyright belong to respective owners. Quotes are made
for educational purposes only in compliance with the fair use doctrine.
Disclaimer:
- The statements, views and opinions presented on
this web page are those of the author and are not endorsed by, nor do they necessarily
reflect, the opinions of the author present and former employers, SDNP or any other
organization the author may be associated with.
- We do not warrant the correctness of the information provided or its
fitness for any purpose
- In no way this site is associated with or endorse cybersquatters
using
the term "softpanorama" with other main or country domains (e.g. softpanorama.com) with
bad faith intent to profit from the goodwill belonging to
someone else.
Last modified:
August 15, 2009