2016-08-05 16 views
1

die folgende Bash-Skript nehmen:

#!/bin/bash 

ls /sdfg 

if [ $? -gt 0 ] 
then 
     echo "Command failed: $?" 
else 
     echo "Command succeeded: $?" 
fi 

Der Ausgang wird sein:

ls: cannot access /sdfg: No such file or directory 
Command failed: 0 

Die gescheiterte Befehl ls die tatsächlich den Wert 2, wenn Anweisung Fänge dieses, und echo Befehl gescheitert, aber warum tut $? auf Null gebracht werden? Es sieht so aus, als ob die if/then Zeilen als neuer Befehl behandelt werden.

+2

'[' ist ein Befehl ("Test" genannt) – Mat

Antwort

2

[ ist eigentlich eine binäre, nicht nur einige Satzzeichen:

$ ls -l /usr/bin/[ 
-rwxr-xr-x 1 root root 51920 Feb 18 07:37 /usr/bin/[ 
$ /usr/bin/[ --version 
[ (GNU coreutils) 8.25 
Copyright (C) 2016 Free Software Foundation, Inc. 

und auf einigen Systemen ein symbolischer Link auf test sein kann.

Also hier

if [ $? -gt 0 ] 

$? ist das Ergebnis Ihres ls Anruf, aber hier

echo "Command failed: $?" 

$? ist das Ergebnis [ in der vorhergehenden Zeile ausgeführt zu haben.

Wenn Sie $? von einem Befehl mehrere Male testen möchten, müssen Sie es in eine temporäre var stopfen müssen:

ls blahblah 
temp=$? 
if [ $temp ... ] 
if [ $temp ... ] 
+0

Okay, großartig. Danke für die ausführliche Erklärung. –

+1

Die Temp-Variable ist nicht notwendig, wenn Sie vermeiden, '' ''' zu laufen, das sowieso oft ein Antipattern ist. – tripleee

2

Sie selten benötigen, sollten $? ausdrücklich ohnehin zu untersuchen, da das zu tun ist Zweck von if (und andere bedingte Builtins wie while). Der richtige Weg, das zu schreiben ist

if ls /sdfg; then 
    echo "Command succeeded: $?" 
else 
    echo "Command failed: $?" 
fi 

Beachten Sie, wie der Fehlerfall ist nun der else Zweig. (Wenn Sie nicht besonders darauf achten, den Fehler-Exit-Code beizubehalten, können Sie if ! ls ... verwenden und den Erfolgszweig in der else beibehalten, aber Ihre Frage scheint speziell zu sein, es zu erhalten, die Negation mit ! wird nicht tun.)

2

Collect den Rückgabewert sofort nach dem Befehl, wenn Sie es wieder verwenden werden getestet werden:

#!/bin/bash 

# best-practice: collect *on the same line*, so any logging added in the future doesn't 
# ...change your exit status. 
ls /sdfg; retval=$? 

if [ $retval -gt 0 ]; then 
     echo "Command failed: $retval" # 
else 
     echo "Command succeeded: $retval" 
fi 

jedoch die beste Praxis direkt auf den Befehls des ist Exit-Status zu betreiben ohne aufzu verweisen10 überhaupt:

if ls /sdfg; then 
    echo "Command succeeded: $?" 
else 
    echo "Command failed: $?" 
fi