With the &&
operator between commands, each command runs in sequence, and if any command fails (i.e. returns a nonzero status), the subsequent commands are not executed.
If you want to keep going no matter what, use ;
(or a newline, which is equivalent) instead of &&
. Here, you need to execute one command, and if it succeeds, execute some more commands whether they succeed or not. One way to achieve this is to put these commands inside a brace group (just cd … && mount1; mount2
won't work because this executes mount2
whether or not cd
succeeds due to precedence).
cd /mnt/gentoo && {
mount -t proc none /mnt/gentoo/proc
mount --rbind /dev /mnt/gentoo/dev
mount --rbind /sys /mnt/gentoo/sys
…
}
Alternatively, exit the script or return from the function if cd
fails.
cd /mnt/gentoo || exit $?
mount -t proc none /mnt/gentoo/proc
…
Alternatively, run under set -e
, and put || true
(“or keep going anyway”) after commands that may fail.
set -e
cd /mnt/gentoo
mount -t proc none /mnt/gentoo/proc || true
…
Alternatively, write a command that must succeed: test if /proc
and so on are mounted already.
mount_if_needed () {
eval "mount_point=${\$#}"
awk -v target="$mount_point" '$2 == target {exit(0)} END {exit(1)}' </proc/mounts ||
mount "$@"
}
set -e
cd /mnt/gentoo
mount_if_needed -t proc none /mnt/gentoo/proc
You have another problem where you call chroot
. You've written: “run bash in the chroot. When bash exits, run source
and export
.” That is probably not what you meant. Reading /etc/profile
can be done by making bash a login shell. A possible way to set PS1
may be to set it before running bash, but that won't work if /etc/profile
overrides it, which is common. A better way is to set PS1
in ~/.bashrc
if running inside a chroot (.bashrc
, not .profile
).
chroot . bash --login
Debian uses the following code to set PS1
in /etc/bash.bashrc
based on the content of /etc/debian_chroot
:
# set variable identifying the chroot you work in (used in the prompt below)
if [ -z "$debian_chroot" ] && [ -r /etc/debian_chroot ]; then
debian_chroot=$(cat /etc/debian_chroot)
fi
# set a fancy prompt (non-color, overwrite the one in /etc/profile)
PS1='${debian_chroot:+($debian_chroot)}\u@\h:\w\$ '
Alternatively, for the prompt, use an environment variable instead: run
CHROOT_LOCATION=$PWD chroot bash --login
and put this in ~/.bashrc
or /etc/bash.bashrc
:
if [ -n "$CHROOT_LOCATION" ]; then PS1="($CHROOT_LOCATION)$PS1"; fi
Best Answer
If it refers to commands run just recently, a more efficient way is to reference them with negative numbers:
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. (Usehelp fc
.) It turns out that you can also use negative numbers with it, so you could do the same as above usingThis 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:You can even reverse the order of the range of commands:
fc -1 -4