CD in ein Verzeichnis und führen Sie viele Befehle aus


10

Ich habe folgendes Skript.

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

Ich versuche hier, in ein Verzeichnis zu wechseln /mnt/gentoound einige Befehle auszuführen. Dies funktioniert beim ersten Mal einwandfrei, wenn keiner der Pfade bereitgestellt wurde. Wenn ich es jedoch ausführe, nachdem das Mounten auf einigen Pfaden erfolgreich durchgeführt wurde, wird es nicht fortgesetzt und stoppt beim ersten Fehler. Ich möchte, dass alle Befehle ausgeführt werden, auch wenn die Bereitstellung aufgrund eines Fehlers "bereits bereitgestellt" fehlschlägt. Wie kann ich das machen?

Gibt es auch einen besseren Weg, als alle diese Befehle in einer Zeile zusammenzufassen?

Antworten:


8

Mit dem &&Operator zwischen Befehlen wird jeder Befehl nacheinander ausgeführt. Wenn ein Befehl fehlschlägt (dh einen Status ungleich Null zurückgibt), werden die nachfolgenden Befehle nicht ausgeführt.

Wenn Sie auf ;jeden Fall weitermachen möchten, verwenden Sie stattdessen (oder eine neue Zeile, die gleichwertig ist) &&. Hier müssen Sie einen Befehl ausführen. Wenn dies erfolgreich ist, führen Sie weitere Befehle aus, unabhängig davon, ob sie erfolgreich sind oder nicht. Eine Möglichkeit, dies zu erreichen, besteht darin, diese Befehle in eine Klammergruppe einzufügen ( cd … && mount1; mount2funktioniert einfach nicht, da dies ausgeführt wird, mount2unabhängig davon, ob dies cdaufgrund der Priorität erfolgreich ist oder nicht ).

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

Alternativ können Sie das Skript beenden oder von der Funktion zurückkehren, wenn dies cdfehlschlägt.

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

Alternativ können Sie unter ausführen set -eund || truenach fehlgeschlagenen Befehlen setzen ("oder trotzdem weitermachen").

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

Alternativ können Sie einen Befehl schreiben, der erfolgreich sein muss: Testen Sie, ob /procusw. bereits bereitgestellt sind.

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

Sie haben ein anderes Problem, bei dem Sie anrufen chroot. Sie haben geschrieben: „Führen Sie Bash in the Chroot aus. Wenn Bash beendet ist, renne sourceund export. “ Das haben Sie wahrscheinlich nicht gemeint. Das Lesen /etc/profilekann erfolgen, indem bash zu einer Login-Shell gemacht wird. Eine mögliche Möglichkeit zum PS1Festlegen besteht darin, es vor dem Ausführen von bash festzulegen. Dies funktioniert jedoch nicht, wenn es /etc/profileüberschrieben wird, was häufig der Fall ist. Eine bessere Art und Weise eingestellt ist PS1in , ~/.bashrc wenn innerhalb einer chroot läuft ( .bashrcnicht.profile ).

chroot . bash --login

Debian verwendet den folgenden Code Satz PS1in /etc/bash.bashrcbasierend auf dem Inhalt von /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\$ '

Alternativ können Sie für die Eingabeaufforderung stattdessen eine Umgebungsvariable verwenden: run

CHROOT_LOCATION=$PWD chroot bash --login

und setzen Sie dies in ~/.bashrcoder /etc/bash.bashrc:

if [ -n "$CHROOT_LOCATION" ]; then PS1="($CHROOT_LOCATION)$PS1"; fi

6

Das &&Trennzeichen lautet in diesem Fall "Nur fortfahren, wenn der letzte Befehl erfolgreich war". Wenn Sie ;stattdessen verwenden, werden die Befehle unabhängig von den Ergebnissen nacheinander ausgeführt.

Beachten Sie, dass Sie die Fehler umleiten müssen, wenn dies ein Cron-Job oder etwas anderes ist, das für Dinge, die in stderr geschrieben werden, empfindlich ist /dev/null.


Sie müssen nicht einmal verwenden ;. Setzen Sie einfach jeden Befehl in eine eigene Zeile, aber Sie müssen auch den loswerden set -e. Wenn Sie sich nicht für Befehlsfehler interessieren, warum überhaupt verwenden set -e? (Ich kenne die Frage, die für eine Zeile gestellt wurde, aber das macht in einem Skript keinen Sinn).
Camh

Vermutlich handelt es sich nicht um ein Skript, das als Quelle gedacht ist (obwohl es dann keinen Sinn macht, eine She-Bang-Linie zu haben), da es sich um die Einstellungen PS1 handelt.
Stéphane Chazelas

0

Setzen Sie den Befehl in Klammern - (), damit Sie am Ende zum aktuellen Verzeichnis oder zur aktuellen CD zurückkehren. Wenn Sie dies in eine Datei einfügen und ausführen: sh ./my_script.sh, werden die Befehle im geänderten Verzeichnis ausgeführt.

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

In Bash

set -e 

führt dazu, dass das Skript beim ersten Fehler nicht mehr ausgeführt wird. Da Sie + e gesetzt haben, würde ich annehmen, dass das Skript weiterhin ausgeführt werden soll, wenn ein Befehl fehlschlägt.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.