Suppose I want to execute a sequence of four commands that I have executed before. If the first one is 432 in the command-history, then I could do:
$ !432; !433; !434; !435
I'm curious, is there a more efficient way to accomplish this?
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems. It only takes a minute to sign up.
Sign up to join this communitySuppose I want to execute a sequence of four commands that I have executed before. If the first one is 432 in the command-history, then I could do:
$ !432; !433; !434; !435
I'm curious, is there a more efficient way to accomplish this?
If it refers to commands run just recently, a more efficient way is to reference them with negative numbers:
!-4; !-3; !-2; !-1
Also, once you do it, your last history entry will contain the whole chain of commands, so you can repeat it with !!
.
Edit:
If you haven't already, get familiar with the great builtin function fc
, mentioned by Gilles. (Use help fc
.) It turns out that you can also use negative numbers with it, so you could do the same as above using
eval "`fc -ln -4 -1`"
This has one caveat, though: after this, the eval
line is stored in the history as the last command. So if you run this again, you'll fall into a loop!
A safer way of doing this is to use the default fc
operation mode: forwarding the selected range of commands to an editor and running them once you exit from it. Try:
fc -4 -1
You can even reverse the order of the range of commands: fc -1 -4
To view a range of commands in the history use the built-in fc
command:
fc -ln 432 435
To execute them again:
eval "$(fc -ln 432 435)"
man fc
doesn't give me anything. What does fc
stand for? What other options are there?
Nov 17, 2011 at 3:00
help fc
... and also help help
.... help: help [-dms] [pattern ...] Display information about builtin commands.
fc
stands for "find command" or "fix command".
Oct 20, 2015 at 5:49
There is a nice and alternate way to run a number of commands in sequence from the Bash history:
instead of using history substitute (!432
or !-4
), you can search through the history with Ctrl+r, and once you've found the first command you want to run, hit Ctrl+o (operate-and-get-next) instead of the return key
This will launch the command and propose the next one from the history.
You can hit Ctrl+o as many time as you wish, and end the sequence either with return for a last one, or Ctrl+c to stop without launching it.
Ctrl-o
it just outputs a literal ^o
and breaks my (reverse-i-search)
. Maybe there is some other setting involved.
Mar 11, 2018 at 11:50
To execute the commands immediately rather than edit them, here is a syntactically slimmer version of Giles answer using eval:
fc -e: 432 435
The colon argument to -e is the bash noop, which has the effect of skipping the "open in an editor" step that fc wants. Also, now the (recent) history will contain the actual commands from history, rather than the eval statement.
fc
for loop and xsel
This works well when I want to concatenate and re-run the last n commands multiple times:
fcn() (
from="${1:-2}"
to="${2:-1}"
if [ "$from" -ne "$to" ]; then
for i in `seq "$from" -1 "$(($to + 1))"`; do
printf "$(fc -ln -${i} -${i}) && "
done
fi
printf "$(fc -ln -${to} -${to})"
)
Then:
$ echo a
a
$ echo b
b
$ echo c
c
$ fcn 3 1 | xsel -b
$ # Paste.
$ echo a && echo b && echo c
a
b
c
$ # Paste again if you feel like it.
$ echo a && echo b && echo c
a
b
c
Or for larger commands that might need some editing:
fcn 3 1 >cmds.sh
vi cmds.sh
bash cmds.sh
bash cmds.sh
fcn 3 1 >cmds.sh
vi cmds.sh
bash cmds.sh
bash c
history -p \!43{2..5}
to print commands 432 through 435 to the terminal, suitable for subsequent copy/paste.