Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

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?

share|improve this question
add comment

3 Answers

up vote 5 down vote accepted

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
share|improve this answer
    
+1 Thanks Gilles for your time for explaining. –  Dilawar Mar 14 '13 at 8:37
add comment

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.

share|improve this answer
    
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 '13 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. –  Stephane Chazelas Mar 13 '13 at 8:59
add comment

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.

share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.