перейдите в каталог и выполните много команд

10

У меня есть следующий сценарий.

#!/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" 

Здесь я пытаюсь перейти в каталог /mnt/gentooи выполнить несколько команд. Это работает нормально в первый раз, когда ни один из путей не был смонтирован. Но если я запускаю его после того, как монтирование было успешно выполнено на некоторых путях, оно не продолжается и останавливается при первом сбое. Я хочу, чтобы все команды выполнялись даже в случае сбоя монтирования из-за ошибки «уже смонтирован». Как я могу это сделать?

Также есть ли лучший способ, чем объединить все эти команды в одну строку?

Дилавар
источник

Ответы:

8

С &&оператором между командами каждая команда выполняется последовательно, и если какая-либо команда не выполняется (т.е. возвращает ненулевой статус), последующие команды не выполняются.

Если вы хотите продолжать, несмотря ни на что, используйте ;(или новую строку, что эквивалентно) вместо &&. Здесь вам нужно выполнить одну команду, и, если она успешна, выполнить еще несколько команд, независимо от того, успешно они или нет. Один из способов добиться этого - поместить эти команды в группу фигурных скобок (просто cd … && mount1; mount2не будет работать, потому что это выполняется mount2независимо от того, cdуспешно ли выполняется приоритет).

cd /mnt/gentoo && {
  mount -t proc none /mnt/gentoo/proc
  mount --rbind /dev /mnt/gentoo/dev
  mount --rbind /sys /mnt/gentoo/sys
  
}

Либо выйдите из скрипта или вернитесь из функции, если cdпроизойдет сбой.

cd /mnt/gentoo || exit $?
mount -t proc none /mnt/gentoo/proc

В качестве альтернативы, запустите команду set -eи поставьте || true(«или продолжайте в любом случае») после команд, которые могут потерпеть неудачу.

set -e
cd /mnt/gentoo
mount -t proc none /mnt/gentoo/proc || true

В качестве альтернативы, напишите команду, которая должна завершиться успешно: проверьте, если /procи так уже смонтированы.

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

У вас есть другая проблема, когда вы звоните chroot. Вы написали: «запустите bash в chroot. Когда выйдет Баш, беги sourceи export». Это, вероятно, не то, что вы имели в виду. Чтение /etc/profileможно сделать, сделав bash оболочкой входа в систему. Возможным способом установки PS1может быть установка его перед запуском bash, но это не сработает, если /etc/profileпереопределит его, что является распространенным явлением. Лучший способ заключается в наборе PS1в ~/.bashrc при работе в изолированном окружении ( .bashrcне.profile ).

chroot . bash --login

Debian использует следующий код для установки PS1на /etc/bash.bashrcоснове содержимого /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\$ '

В качестве альтернативы вместо приглашения используйте переменную среды: run

CHROOT_LOCATION=$PWD chroot bash --login

и вставьте это в ~/.bashrcили /etc/bash.bashrc:

if [ -n "$CHROOT_LOCATION" ]; then PS1="($CHROOT_LOCATION)$PS1"; fi
Жиль "ТАК - перестань быть злым"
источник
6

В &&этом случае разделитель говорит: «Продолжать, только если последняя команда была успешной». Если вы используете ;вместо этого, команды будут выполняться последовательно, независимо от результатов.

Обратите внимание, что если это задание cron или что-то еще, чувствительное к вещам, записываемым в stderr, вам нужно перенаправить ошибки в /dev/null.

Flup
источник
Вам даже не нужно использовать ;. Просто поместите каждую команду в отдельную строку, но вы также должны избавиться от set -e. Если вас не волнует сбой команды, зачем вообще использовать set -e? (Я знаю вопрос, заданный для одной строки, но это не имеет смысла в сценарии).
Cam
Предположительно, это не сценарий, и он предназначен для поиска (хотя в этом случае не имеет смысла использовать черту), поскольку он настроен на PS1.
Стефан Шазелас
0

Поместите команду в скобки - (), чтобы вы вернулись в текущий каталог, или cd - в конце. Если вы поместите это в файл и запустите его: sh ./my_script.sh, он запустит команды в измененном каталоге.

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

В баш

set -e 

приведет к остановке скрипта при первом сбое. Поскольку вы установили + e, я бы предположил, что вы хотите, чтобы скрипт продолжал работать в случае сбоя команды.

Interlated
источник