Was ist der Unterschied zwischen der Verwendung von; und Ausführen eines Skripts

7

Ich verwende bashals meine Haupt-Shell, aber es ist eine offene Frage und Antwort für Muscheln, die nicht bashsehr willkommen sind.

Wenn ich interaktiv tippe

#original line 
#wget http://something.com && unzip something && mv -f something /home/poney/ 
#new line
wget http://something.com ; unzip something ; mv -f something /home/poney/

Macht es einen Unterschied in Bezug auf Ausführungsstapel, Reihenfolge, Speicher, Interpretation und Berechtigung im Vergleich zu einem Skript, das diese Zeile enthält:

#!/bin/bash
wget http://something.com
unzip something 
mv -f something /home/poney/

PS:

mit der Ausnahme, dass die Ausführung eines Skripts offensichtlich kürzer ist als die Eingabe eines 3-Befehls hintereinander.

Kiwy
quelle
1
Ich bin nicht wirklich überzeugt von dem Duplikat, weil ich auch nach Pur Scripting frage, das meiner Meinung nach anders ist als die interaktive Shell.
Kiwy
@ Kiwy Aber du hast den Titel komplett geändert. Es ist jetzt viel klarer.
Bernhard

Antworten:

17

Ja, es gibt einen großen Unterschied. &&ist kurzgeschlossen , daher würde der nachfolgende Befehl nur ausgeführt, wenn der vorherige mit einem Exit-Code von zurückgegeben würde 0.

Zitat aus dem Handbuch :

Ausdruck1 && Ausdruck2

True if both expression1 and expression2 are true.

Auf der anderen Seite enthält ein Skript

expression1
expression2

würde den zweiten Ausdruck ausführen, selbst wenn der erste fehlschlägt. (Es sei denn, Sie haben das Skript angegeben, das bei einem Fehler beendet werden soll set -e.)


EDIT: In Bezug auf Ihren Kommentar, ob:

command1; command2

ist das gleiche wie:

command1
command2

Die Antwort ist normalerweise . Bash analysiert einen gesamten Anweisungsblock, bevor einer davon ausgewertet wird. EIN ; bewirkt nicht, dass der vorherige Befehl ausgewertet wird. Wenn sich der vorherige Befehl darauf auswirken würde, wie der nachfolgende analysiert wird, würden Sie den Unterschied bemerken.

Stellen Sie sich eine Datei vor, die Aliase enthält, und rufen Sie sie aliasmit einem Eintrag auf:

alias f="echo foo"

Betrachten Sie nun ein Skript, das Folgendes enthält:

shopt -s expand_aliases
source ./alias
f

und eine andere mit:

shopt -s expand_aliases; source ./alias; f

dann könnten Sie denken, dass beide die gleiche Ausgabe erzeugen würden.

Die Antwort ist nein. Der erste würde produzieren, fooaber der zweite würde berichten:

... f: command not found

Zur weiteren Klärung ist es nicht expand_aliasesdas Problem. Das Problem ist auf die Tatsache zurückzuführen, dass eine Aussage wie:

alias f="echo foo"; f

würde auf einmal analysiert werden . Die Shell weiß nicht wirklich, was fist, dies führt dazu, dass der Parser erstickt.

devnull
quelle
OK, dann hätte meine Frage mitcommand ; command2; command3
Kiwy
@ Kiwy Du meinst ;statt &&?
devnull
In der Tat führt der Kontext der Ausführung dazu, dass sich die Ausführung eines Skripts und eines interaktiven Skripts hauptsächlich aufgrund der Bash-Variablen unterschiedlich verhält.
Kiwy
@ Kiwy Umgebungsvariable?
devnull
2
@terdon Bash analysiert einen gesamten Anweisungsblock, bevor einer davon ausgewertet wird. A ;bewirkt nicht, dass der vorherige Befehl ausgewertet wird . Daher drosselt der Parser, wenn er auf einen unbekannten Befehl stößt.
devnull
6

Ja, &&ist Zustand. Der Befehl dahinter wird nur gestartet, wenn der vorherige zurückgegeben wird 0(endet ohne Fehler). Auf der anderen Seite hat Ihr Skript diese Kontrolle nicht, wenn z. wget endet mit einem Fehler, es wird fortgesetzt und versucht, nichts zu entpacken und zu verschieben.

Onliner für Ihr Skript ist:

wget http://something.com ; unzip something ; mv -f something /home/poney/
stderr
quelle
semi colonEntspricht das in diesem Fall dem Jumpline in meinem Skript?
Kiwy
@ Kiwy, ja das ist es.
Graeme
2

Ein weiterer Unterschied zu dem genannten besteht darin, dass Ihr Shell-Skript in einer separaten Shell ausgeführt wird, sodass Änderungen an der Umgebung nicht weitergegeben werden. Zum Beispiel, wenn Sie Ihre interaktive Shell eingeben

test -f foo && file=foo || file=other

dann enthält Ihre interaktive Shell eine Variable file(mit der Sie lesen können $file), die enthält, fooob die Datei foo existiert und eine reguläre Datei ist, und otheransonsten. Wenn Sie dasselbe in ein Shell-Skript einfügen und dies von Ihrer interaktiven Shell aus aufrufen, wird die Variable filein Ihrer interaktiven Shell nicht festgelegt (aber natürlich wird sie in Ihrem Shell-Skript festgelegt, sodass Sie sie in weiteren Befehlen verwenden können darin).

Celtschk
quelle