Wie genau funktioniert "/ bin / ["?

50

Ich bin immer wieder überrascht, dass sich in dem Ordner /binein [Programm befindet.

Heißt das, wenn wir etwas machen wie if [ something ]:?

Wenn Sie das [Programm explizit in einer Shell aufrufen, werden Sie nach einer Entsprechung gefragt. ]Wenn Sie die schließende Klammer angeben, scheint es nichts zu tun, unabhängig davon, was zwischen den Klammern steht.

Es erübrigt sich zu erwähnen, dass der übliche Weg, Hilfe zu einem Programm zu erhalten, nicht funktioniert, dh weder funktioniert man [noch [ --help.

Bregalad
quelle
11
@IporSircer [bezieht sich auf testBefehl, aber nicht expr, so sollte es seinman test
Sergiy Kolodyazhnyy
8
man '['funktioniert gut für mich - entweder hast du vergessen zu zitieren [oder du hast eine andere Definition von "funktioniert".
Toby Speight
3
Einige Warnungen: [Wertet die Argumente aus, sodass Sie zwischen allen Leerzeichen einfügen müssen. [ a=b ]ist kein Vergleich: es ist immer wahr (es ist eine einzelne Zeichenfolge: "a = b", die immer als wahr ausgewertet wird ) und Sie sollten die Anzahl der Argumente auf 4 begrenzen (auch wenn die jüngsten Implementierungen mehr zulassen. Die Beschränkung auf 4 macht es portabler. Beispiel: [ "a" = "b" ]Hat bereits 4 Argumente: "a" = "b" und das nicht notwendige Ende des Tests arg: "]"). Wenn Sie mehr brauchen: Kettentests mit zum Beispiel:if [ "$Var_a" = "foo" ] && [ "$Var_b" = "bar" ] ; then : do something ; fi
Olivier Dulac
1
@OlivierDulac a !für sich (ohne Flucht und ohne Anführungszeichen) wird nicht ersetzt und wäre noch besser if ! [ .... Alle Bash-Erweiterungen, die verwendet werden, !beinhalten mindestens die Erweiterung für andere Charaktere
muru
3
Sie sollten auch beachten, dass es auch ein [-builtin gibt bash(und möglicherweise auch andere Shells), und dass dies anstelle von verwendet werden kann /bin/[. Es gibt auch den testBefehl -command, der auf vielen Systemen eine symbolische Verknüpfung zu /bin/[(oder umgekehrt) darstellt, auf anderen jedoch einen separaten Befehl.
Baard Kopperud

Antworten:

63

Der [Befehl hat die Aufgabe, Testausdrücke auszuwerten. Es wird mit dem Exit-Status 0 (das heißt true ) zurückgegeben, wenn der Ausdruck in true aufgelöst wird, und mit etwas anderem (was false bedeutet ).

Es ist nicht so, dass es nichts tut, es ist nur so, dass das Ergebnis in seinem Ausgangsstatus zu finden ist. In einer Shell können Sie den Exit-Status des letzten Befehls in $?für Bourne-ähnliche Shells oder $statusin den meisten anderen Shells (fish / rc / es / csh / tcsh ...) abrufen.

$ [ a = a ]
$ echo "$?"
0
$ [ a = b ]
$ echo "$?"
1

In anderen Sprachen wie perlz. B. wird der Exit-Status beispielsweise im Rückgabewert von zurückgegeben system():

$ perl -le 'print system("[", "a", "=", "a", "]")'
0

Beachten Sie, dass alle modernen Bourne-ähnlichen Shells (und fish) einen eingebauten [Befehl haben. Das one in wird /binnormalerweise nur ausgeführt, wenn Sie eine andere Shell verwenden oder wenn Sie Dinge wie env [ foo = bar ]oder find . -exec [ -f {} ] \; -printoder den perlobigen Befehl ausführen ...

Der [Befehl ist auch unter dem testNamen bekannt. Beim Aufruf als testist kein abschließendes ]Argument erforderlich .

Während Ihr System möglicherweise keine Manpage für hat [, hat es wahrscheinlich eine für test. Beachten Sie jedoch erneut, dass dies die /bin/[oder /bin/test-Implementierung dokumentieren würde . Um mehr über die [in Ihrer Shell integrierten Funktionen zu erfahren , sollten Sie stattdessen die Dokumentation zu Ihrer Shell lesen.

Weitere Informationen zum Verlauf dieses Dienstprogramms und zum Unterschied zum [[...]]Ausdruck "ksh test" finden Sie in den folgenden Fragen und Antworten .

Stéphane Chazelas
quelle
Wie immer gut. Vielleicht möchten Sie den Kommentaren hinzufügen, die ich unter der @Bregalad-Frage hinzugefügt habe? oder vielleicht ein paar extra? Auf diese Weise ist die Antwort auf "Wie genau funktioniert es?" Noch vollständiger (ich stelle fest, dass Sie bereits genauere Informationen zu "]" angegeben haben als ich ^^)
Olivier Dulac
„Alle Bourne-ähnlichen Muscheln (und Fische) haben einen eingebauten [Befehl].“ Das stimmt in der Praxis im 21. Jahrhundert, aber ich bin mir ziemlich sicher, dass ich eine Muschel ohne verwendet habe [. Ich erinnere mich nicht, ob es eine Bourne-Variante oder eine antike Version von Esche war.
Gilles 'SO- hör auf böse zu sein'
@Gilles Die Bourne-Shell wurde sowohl [als auch testals integrierte Komponente in Unix System III implementiert . Davor gab es keinen [und es testgab nur einen externen Binärbefehl.
Juli
@ Gilles, die ursprüngliche Asche hatte einen eingebauten Test (zusammengeführt mit expr), aber optional . Laut in-ulm.de/~mascheck/various/ash hatten BSDs erst um 2000 einen Test eingebaut. Ich habe "modern" hinzugefügt.
Stéphane Chazelas
Warum in aller Welt würdest du das tun wollen find . -exec [ f {} ] \; -print? Der Befehl find . -type f -printwürde dasselbe so viel effizienter machen ...
Dies ist nicht mein richtiger Name
41

Ich bin immer wieder überrascht, dass sich in dem Ordner /binein [Programm befindet.

Sie haben Recht, überrascht zu sein. Dies ist einer der seltenen POSIX-Befehle mit dem Dienstprogramm null ( :), der die Konvention zulässiger Zeichen für die Befehlsdatei (portabler Zeichensatz für Dateinamen) nicht einhält.

Heißt das, wenn wir etwas machen wie if [ something ]:?

Genau, aber es kann auch ohne verwendet werden if.

Wenn Sie das [Programm explizit in einer Shell aufrufen, werden Sie nach einer Entsprechung gefragt. ]Wenn Sie die schließende Klammer angeben, scheint es nichts zu tun, unabhängig davon, was zwischen den Klammern steht.

Es macht nichts sichtbares, aber es macht tatsächlich das Gleiche wie bei Verwendung mit if, dh es setzt den Exit-Status auf 0 (wahr) oder irgendetwas anderes (falsch), je nachdem, was Sie in die Klammern setzen. Es ist (aus einem Grund) dasselbe Verhalten wie der testBefehl; Der einzige Unterschied ist, dass es nach dem Ende sucht ]. Siehe man testfür weitere Einzelheiten.

Es erübrigt sich zu erwähnen, dass der übliche Weg, Hilfe zu einem Programm zu erhalten, nicht funktioniert, dh weder funktioniert man [noch [ --help.

Das hängt von Ihrem Betriebssystem ab. man [Funktioniert auf jeden Fall für ein paar gängige Gnu / Linux-Distributionen, aber nicht für Solaris.

[ --helpfunktioniert je nach Implementierung möglicherweise oder auch nicht, da die Syntax sowieso durchbrochen wird und die Endung fehlt ]. Darüber hinaus ist der POSIX - Standard für die test/ [Befehlsregeln ausdrücklich alle Optionen, einschließlich der --Option Beendigung so beide [ --help ]und test --helpNotwendigkeit zurückzukehren trueund nach Design schweigen. Beachten Sie, dass das, was Sie in oder nach eckigen Klammern setzen [und wie Optionen (z. B. und dergleichen) aussehen -f file, -n stringkeine Optionen, sondern Operanden sind .

Alle modernen Bourne Stil Shell Interpreter (wie bash, ksh, dashund zshein paar zu nennen) die Umsetzung test/ [intern als builtin Dienstprogramm so , wenn Sie sie verwenden, das richtige Handbuch Seite verweisen könnte derjenige der Schale sein, nicht das testeine.

Vor Unix System III (1981) implementierte die Bourne-Shell das testDienstprogramm nicht als eingebautes Dienstprogramm, sodass nur die Implementierung externer Binärbefehle verfügbar war. [Bis Unix System III gab es weder einen Befehl (intern noch eingebaut), so dass Sie beispielsweise unter Unix Version 7 Folgendes eingeben mussten:

if test something ; then

Anstatt von:

if [ something ] ; then

jlliagre
quelle
"man [arbeitet definitiv für mich an den Gnu / Linux-Distributionen des Mainstreams" Hmm .. Centos (zugegebenermaßen immer noch 6.8) ist eindeutig nicht mainstream genug :) man testfunktioniert aber nicht man [ Andererseits weiß meine Cygwin-Umgebung davon man [!
Adam
1
@Adam Ja, Sie haben Recht, das ist aktueller als ich dachte, obwohl ich nicht alle gängigen Linux-Distributionen geschrieben habe, nur dass es für mich funktioniert hat (dh für die, die ich getestet habe). Das ist der OL 7.2 (RHEL 7.2) Klon und Mint 17.1 (Ubuntu 14.04).
12.
man [scheint auf Manjaro (Arch Linux basiert) nicht zu funktionieren. Das Handbuch für testListen [ --helpals gültiger Aufruf, der Hilfe zeigen sollte, aber interessanterweise nicht, und sich stattdessen über ein Fehlen beschwert ], genauso wie bei --version. Das Hinzufügen von ]hat keine Auswirkung, daher scheint es unmöglich zu sein, Hilfe zu erhalten, außer von man test.
Darkhogg
@ Darkhogg Sie können versuchen, /usr/bin/[ --helpoder /bin/[ --help.
Juli
1
@jlliagre Du hast vollkommen recht, ich habe die Builtins benutzt. env [ --helpsowie /usr/bin/[ --helpganz gut funktionieren (obwohl ich zitieren muss /usr/bin/[oder zsh sich beschwert).
Darkhogg
10

[ist eigentlich häufiger als testBefehl bekannt. In der Regel wird dieser Befehl nur verwendet, um Ausdrücke auszuwerten und ihre Bedingung zurückzugeben - wahr oder falsch. Es wird häufig in if-then-else-fiAnweisungen verwendet, obwohl es auch außerhalb von ifAnweisungen verwendet werden kann, um andere Befehle über Shell-Befehle &&oder ||Operatoren wie diese bedingt auszuführen .

$ [ -e /etc/passwd  ] && echo "File exists"
File exists

$ test -e /etc/passwd && echo "File exists"
File exists

Insbesondere wird die Auswertung über den Exit-Status an andere Befehle übermittelt. Einige Programme geben möglicherweise den Exit-Status aus, um verschiedene Ereignistypen anzuzeigen - ein erfolgreich abgeschlossenes Programm, ein Fehler eines bestimmten Typs, der während der Ausführung auftritt, oder Syntaxfehler. Im Fall des testBefehls gibt es " 0wahr" und " 1falsch". Wie Stephan betonte, erzeugen Syntaxfehler den Exit-Status von 2.

Die Position hängt von Ihrem System ab und erklärt auch, warum Sie die Manpage nicht gesehen haben, als Sie dies getan haben man [. Zum Beispiel unter FreeBSD /bin. Unter Linux (oder in meinem speziellen Fall Ubuntu 16.04) ist es in /usr/bin/. Wenn Sie man [oder man testauf einem Linux-System arbeiten, wird dieselbe Dokumentation geöffnet. Es ist auch wichtig zu beachten, dass Ihre Shell möglicherweise eine eigene Implementierung von hat test.

Es sollte auch beachtet werden, dass dieser Befehl Probleme aufweist , die durch die Implementierung der Korn-Shell (allgemein als "Bedingungsausdruck" -Referenz mit doppelten eckigen Klammern bezeichnet [[ "$USER" = "root" ]]) behoben werden sollen. Diese Funktion wird auch von anderen Shells wie bashund verwendet zsh.

Sergiy Kolodyazhnyy
quelle
/usr/bin/auch für Amazon Linux.
Franklinsijo
@ StéphaneChazelas Danke. Antwort entsprechend bearbeitet
Sergiy Kolodyazhnyy
3

Weder funktioniert man [noch[ --help

In einigen Distributionen (zB Ubuntu) man [folgt ein Symlink zu test(1). Bei anderen (zB Arch) ist dies nicht der Fall. (Aber die testManpage dokumentiert auch die Verwendung von [)


type -a [ zeigt Ihnen, dass es sowohl eine eingebaute Shell als auch eine ausführbare Datei gibt.

$ type -a [
[ is a shell builtin
[ is /usr/bin/[

bash-builtin gibt [ --helpnur eine Fehlermeldung aus. (Da es sich jedoch um ein eingebautes Programm handelt, können Sie help [die bash-Manpage / docs verwenden oder sich diese ansehen.)

/usr/bin/[ --help gibt die vollständige Hilfeausgabe aus (für die GNU Coreutils-Version), die mit Folgendem beginnt:

$ /usr/bin/[ --help
Usage: test EXPRESSION
  or:  test
  or:  [ EXPRESSION ]
  or:  [ ]
  or:  [ OPTION
Exit with the status determined by EXPRESSION.

      --help     display this help and exit
      --version  output version information and exit

und beschreibt dann die erlaubte Syntax für EXPRESSION.

Dies ist ein weiterer Weg, wie Sie das herausgefunden haben [und testgleichwertig sind.


Übrigens, wenn Sie bash programmieren (oder Schreiben Einzeiler interaktiv), würde ich empfehlen , [[statt [. Es ist in mehrfacher Hinsicht besser, siehe Links in Sergs Antwort.

Peter Cordes
quelle
2

[Der Befehl gibt den Ausgangsstatus Null zurück, wenn der in den Argumenten enthaltene Ausdruck als wahr und der in den Argumenten enthaltene Ausdruck als falsch gilt. Es schlägt auch mit einer Fehlermeldung fehl, wenn das letzte Argument nicht vorhanden ist ](dies geschieht aus rein ästhetischen Gründen).

Z.B:

[ hello ]
echo "Exit-status of [ hello ] is:" $?
[ abc = abc ]
echo "Exit-status of [ abc = abc ] is:" $?
[ ]
echo "Exit-status of [ ] is:" $?
[ abc = def ]
echo "Exit-status of [ abc = def ] is:" $?

… Gibt aus:

Exit-Status [hallo] ist: 0       - weil nicht leere Zeichenfolge wahr betrachtet wird 
Exit-Status [abc = abc] ist: 0   - weil 'abc' wirklich gleiche ist wie 'abc' 
Exit-Status [] ist : 1             - weil leere Zeichenkette als falsch betrachtet wird. Der 
Exit-Status von [abc = def] ist: 1   - weil sich 'abc' wirklich von 'def' unterscheidet.

Allerdings rufen bash und viele andere Shells in diesen Fällen in der Regel nicht /bin/[(oder /usr/bin/[) auf, sondern rufen den eingebauten Befehl mit genau demselben Verhalten auf (nur aus Leistungsgründen). Zum Aufrufen /bin/[(nicht des in die Shell eingebauten Ersatzzeichens) müssen Sie entweder den Pfad explizit angeben (z /bin/[ hello ].] B. müssen Sie dem Verzeichnisnamen nicht das Präfix voranstellen ) oder die Shell so konfigurieren, dass kein eingebauter Ersatzzeichen verwendet wird (z. B. enable -n [in bash).

PS: Wie schon in anderen Antworten gesagt, [ist das verwandt mit test. Aber testim Gegensatz zu [, erfordert nicht ]als letztes Argument (und nicht erwarten , dass es überhaupt, das Hinzufügen von zusätzlichen ]zu testArgumenten kann es dazu führen , mit der Fehlermeldung fehlschlagen oder falsches Ergebnis zurück) . Das /bin/testund /bin/[kann in dieselbe Datei aufgelöst werden (z. B. eine ist symbolisch verknüpft ; in diesem Fall wird die Verhaltensumleitung wahrscheinlich durch Analysieren des aktuell aufgerufenen Befehls im test/ [code selbst implementiert ) oder in verschiedene Dateien. Für test, Shell auch beruft , in der Regel Einbau-Surrogat, es sei denn , Pfad explizit angegeben wird ( /bin/test) oder es konfiguriert ist , dies nicht zu tun (enable -n test).

PPS: Im Gegensatz zu testund [ist modern ifnie eine echte Datei. if commandA; then commandB; fiDies ist Teil der Shell-Syntax (z. B. Bash): (Zeilenumbrüche können anstelle von Semikolons verwendet werden). commandBWird ausgeführt, wenn das Programm commandAmit dem Status Null verlassen wird. Dies passt perfekt zum Verhalten von testoder [und erlaubt es, sie wie if [ "$a" = foo ]; then …; fi (oder if test "$a" = foo; then …; fi- nur weniger lesbar) zu kombinieren . Moderne Skripte verwenden jedoch häufig [[anstelle von testoder [, was (wie das if) nie eine echte Datei ist, sondern immer ein Teil der Shell-Syntax.

PPPS: Wie für man- Erwarten Sie niemals maneinen Artikel über jeden Befehl in Ihrem Dateisystem. Info auf einigen (auch „echten“, dateibasierte) Befehle fehlen möglicherweise, Informationen zu einigen Shell - Einbauten vielleicht derzeit nicht nur innerhalb eines bestimmten Schale gewidmet Artikel (das der Ort ist , wo Sie ganz sicher Infos finden auf test, [, if, [[). Dennoch haben viele Distributionen explizite man-Artikel für testund [. (Ungefähr --help, es wird testaus offensichtlichen Gründen nicht erkannt : Es muss leise Fälle wie behandeln a=--help; test "$a"; auf einigen Distributionen [ --help(ohne Schließen ]) wird immer noch Hilfe angezeigt, auf einigen nicht.)

Sasha
quelle
3
Beachten Sie, dass dies ifein Befehl bis zu Unix V6 war. Unix V7 (1979) wurde mit der Bourne-Shell (mit ihrem if-then-else-fiKonstrukt) und dem neuen testBefehl geliefert.
Stéphane Chazelas