10

I have following script.

#!/bin/bash
mount /dev/sda6 /mnt/gentoo
set +e
cd /mnt/gentoo && mount -t proc none /mnt/gentoo/proc \
 && mount --rbind /dev /mnt/gentoo/dev \
 && mount --rbind /sys /mnt/gentoo/sys \
 && chroot /mnt/gentoo /bin/bash \
 && source /etc/profile  \
 && export PS1="(chroot)$PS1" 

What I am trying to accomplish here is to change to a directory /mnt/gentoo and execute few commands. This works ok first time when none of the path were mounted. But if I run it after mounting has been successfully performed on some paths, it does not continue and stops on first failure. I want all commands to be executed even if mount is failing due to 'already mounted' error. How can I do this?

Also is there a better way than combining all these commands together in one line?

3 Answers 3

8

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
0
6

The && separator in this case is saying 'only continue if the last command was successful'. If you use ; instead, the commands will execute in sequence irrespective of results.

Note that if this is a cron job or something else sensitive to stuff being written to stderr, you'll need to redirect the errors to /dev/null.

2
  • You don't even need to use ;. Just put each command on its own line, but you also have to get rid of the set -e. If you do not care about command failure, why even use set -e? (I know the question asked for one line, but that makes no sense within a script).
    – camh
    Mar 13, 2013 at 8:45
  • Presumably, it's not a script and is meant to be sourced (though having a she-bang line doesn't make sense then) since it's settings PS1. Mar 13, 2013 at 8:59
0

Put the command in brackets - (), so that you return to the current directory, or cd - at the end. If you put this in a file and run it: sh ./my_script.sh it will run the commands in the changed to directory.

cd  /mnt/gentoo
mount -t proc none /mnt/gentoo/proc
...
cd - 

In bash

set -e 

will cause the script to stop running on the first failure. Because you have set +e I would assume you wanted the script to keep running if a command fails.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .