Jak dokładnie działa „/ bin / [”?

50

Zawsze jestem zaskoczony, że w folderze /binjest [program.

Czy tak się nazywa, gdy robimy coś takiego if [ something ]:?

Wywołując [program jawnie w powłoce, prosi o odpowiedni ], a kiedy dostarczam nawias zamykający, wydaje się, że nie robi nic, bez względu na to, co wstawię między nawiasy.

Nie trzeba dodawać, że zwykły sposób uzyskiwania pomocy na temat programu nie działa, tzn. Ani man [nie [ --helpdziała.

Bregalad
źródło
11
@IporSircer [odnosi się do testpolecenia, ale nie exprpowinno tak byćman test
Sergiy Kolodyazhnyy
8
man '['działa dla mnie dobrze - albo zapomniałeś zacytować, [albo masz inną definicję „dzieł”.
Toby Speight
3
Kilka ostrzeżeń: [ocenia swoje argumenty, więc musisz mieć spacje między nimi wszystkimi. [ a=b ]nie jest porównaniem: zawsze będzie prawdziwe (jest to pojedynczy ciąg: „a = b”, który zawsze jest oceniany jako prawda ) I powinieneś ograniczyć liczbę argumentów do 4 (nawet jeśli ostatnie implementacje pozwolą na więcej .. , ograniczenie do 4. czyni go bardziej przenośnym, na przykład: [ "a" = "b" ]ma już 4 argumenty: „a” „=„ „b” i niepotrzebny koniec testu arg: „]”). Jeśli potrzebujesz więcej: testy łańcuchowe, na przykład:if [ "$Var_a" = "foo" ] && [ "$Var_b" = "bar" ] ; then : do something ; fi
Olivier Dulac
1
@OlivierDulac !sam (bez kształtów i bez cudzysłowów) nie zostanie zastąpiony, a nawet lepiej if ! [ .... Wszystkie używane rozszerzenia bash !obejmują przynajmniej inną postać
muru
3
Powinieneś również zauważyć, że istnieje także [-builtin w bash(i ewentualnie także innych powłokach), i że można go użyć zamiast /bin/[. Istnieje również testpolecenie, które w wielu systemach jest dowiązaniem symbolicznym do /bin/[(lub odwrotnie), ale w innych jest osobnym poleceniem.
Baard Kopperud

Odpowiedzi:

63

Zadaniem tego [polecenia jest ocena wyrażeń testowych. Zwraca ze statusem wyjścia 0 (co oznacza prawda ), gdy wyrażenie przekształca się w prawda, a coś innego (co oznacza fałsz ) w przeciwnym razie.

Nie chodzi o to, że nic nie robi, tylko o to, że jego wynikiem jest status wyjścia. W powłoce możesz dowiedzieć się o statusie zakończenia ostatniego polecenia w $?powłokach podobnych do Bourne'a lub $statusw większości innych powłok (fish / rc / es / csh / tcsh ...).

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

W innych językach, takich jak perl, status wyjścia jest zwracany na przykład w wartości zwracanej system():

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

Zauważ, że wszystkie współczesne powłoki podobne do Bourne'a (i fish) mają wbudowane [polecenie. Ten w /binzwykle byłby wykonywany tylko wtedy, gdy używasz innej powłoki lub gdy robisz rzeczy takie jak env [ foo = bar ]lub find . -exec [ -f {} ] \; -printlub to perlpolecenie powyżej ...

[Polecenia jest również znany pod testnazwą. Po wywołaniu jako testnie wymaga ]argumentu zamykającego .

Chociaż twój system może nie mieć strony podręcznika [, prawdopodobnie ma ją test. Ale znowu zauważ, że dokumentowałoby to /bin/[lub /bin/testwdrożenie. Aby dowiedzieć się o [wbudowanej powłoce, powinieneś przeczytać dokumentację dla swojej powłoki.

Aby uzyskać więcej informacji na temat historii tego narzędzia i różnicy w [[...]]wyrażeniu testowym ksh, możesz zajrzeć do innych pytań tutaj .

Stéphane Chazelas
źródło
Dobrze, jak zwykle. Możesz dodać komentarze, które dodałem pod pytaniem @Bregalad? a może jakieś dodatkowe? W ten sposób odpowiedź będzie jeszcze bardziej kompletna na temat „jak to dokładnie działa” (zauważam, że podałeś już dokładniejsze informacje o „]” niż ja ^^)
Olivier Dulac
„Wszystkie muszle Bourne'a (i ryby) mają wbudowane [polecenie” To prawda w praktyce w XXI wieku, ale jestem prawie pewien, że użyłem muszli bez [. Nie pamiętam, czy był to wariant Bourne'a czy antyczna wersja popiołu.
Gilles „SO- przestań być zły”
@Gilles Bourne powłoki realizowane zarówno [a testjak builtins z System III. Wcześniej nie było [i testbyło tylko zewnętrzne polecenie binarne.
jlliagre
@Gilles, oryginalny jesion miał wbudowany test (połączony z wyrażem), ale opcjonalnie . Według informacji inulm.de/~mascheck/various/ash , BSD nie miały wbudowanego testu aż do około 2000 roku. Dodałem „modern”.
Stéphane Chazelas
Dlaczego na świecie chcesz to zrobić find . -exec [ f {} ] \; -print? Polecenie find . -type f -printzrobi to samo więc znacznie bardziej efektywnie ...
To nie jest moje prawdziwe imię
41

Zawsze jestem zaskoczony, że w folderze /binjest [program.

Masz rację, że jesteś zaskoczony. To jedno z rzadkich poleceń POSIX z narzędziem zerowym ( :), które nie przestrzega konwencji dozwolonych znaków w pliku poleceń (zestaw znaków w przenośnej nazwie pliku).

Czy tak się nazywa, gdy robimy coś takiego if [ something ]:?

Dokładnie, ale można go również używać bez if.

Wywołując [program jawnie w powłoce, prosi o odpowiedni ], a kiedy dostarczam nawias zamykający, wydaje się, że nie robi nic, bez względu na to, co wstawię między nawiasy.

Nie robi nic widocznego, ale w rzeczywistości robi to samo, co przy użyciu if, tzn. Ustawia status wyjścia na 0 (prawda) lub cokolwiek innego (fałsz) w zależności od tego, co umieścisz w nawiasach. Jest to (z jakiegoś powodu) to samo zachowanie, co testpolecenie; jedyną różnicą jest to, że szuka zakończenia ]. Zobacz man testszczegóły.

Nie trzeba dodawać, że zwykły sposób uzyskiwania pomocy na temat programu nie działa, tzn. Ani man [nie [ --helpdziała.

To zależy od twojego systemu operacyjnego. man [zdecydowanie działa na mnie w kilku głównych dystrybucjach Gnu / Linux, ale nie działa w Solarisie.

[ --helpmoże działać lub nie w zależności od implementacji, ponieważ i tak łamie składnię, brakuje jej zakończenia ]. Ponadto standardem POSIX dla test/ [polecenia wyraźnie wyklucza wszystkie opcje, w tym --rozwiązaniu opcji tak jak [ --help ]i test --helppotrzebne, aby powrócić truei być cicho przez projekt. Zauważ, że to, co można umieścić w nawiasie lub później [i że wygląda opcji (np -f file, -n stringi lubi) nie są opcje , ale argumenty .

Wszystkie nowoczesne style tłumaczy Bourne shell (jak bash, ksh, dashi zsh, aby wymienić tylko kilka) wdrożyć test/ [użyteczność jako wewnętrznie wbudowane więc podczas korzystania z nich, prawa strona podręcznika odnosi się do może być jednym z muszli, a nie testjeden.

Przed Unix System III (1981) powłoka Bourne'a nie implementowała testnarzędzia jako wbudowanego, więc dostępna była tylko zewnętrzna implementacja poleceń binarnych. [Do Uniksa System III nie było ani polecenia (wewnętrznego ani wbudowanego), więc na przykład w wersji 7 systemu Unix trzeba było wpisać:

if test something ; then

zamiast:

if [ something ] ; then
jlliagre
źródło
„man [zdecydowanie działa dla mnie na głównych dystrybucjach Gnu / Linux” Hmm .. Centos (co prawda nadal 6.8) najwyraźniej nie jest wystarczająco główny nurtem :) man testdziała, ale nie man [ Z drugiej strony moje środowisko cygwin wie o tym man [!
Adam
1
@Adam Tak, masz rację, to jest nowsze niż myślałem, chociaż nie napisałem wszystkich głównych dystrybucji Linuksa, po prostu to działało dla mnie (tj. Na tych, które testowałem). To jest klon OL 7.2 (RHEL 7.2) i Mint 17.1 (Ubuntu 14.04).
jlliagre
man [wydaje się nie działać na Manjaro (oparty na Arch Linux). Podręcznik dla testlist [ --helpjako prawidłowego wywołania, które powinno pokazywać pomoc, ale co ciekawe nie, i zamiast tego narzeka na brakujące ], tak jak z --version. Dodanie ]nic nie robi, więc wydaje się niemożliwe uzyskanie pomocy innej niż man test.
Darkhogg
@Darkhogg Możesz spróbować /usr/bin/[ --helplub /bin/[ --help.
jlliagre
1
@jlliagre Masz całkowitą rację, korzystałem z wbudowanych funkcji. env [ --helpjak również /usr/bin/[ --helpdziała całkowicie dobrze (chociaż muszę cytować /usr/bin/[lub narzeka Zsh).
Darkhogg,
10

[jest właściwie bardziej znany jako testpolecenie. Typowe użycie tego polecenia polega po prostu na ocenie wyrażeń i zwróceniu ich stanu - true lub false. Jest często używany w if-then-else-fiinstrukcjach, chociaż można go używać poza ifinstrukcjami, aby warunkowo uruchamiać inne polecenia za pośrednictwem powłoki &&lub ||operatorów, podobnie jak w przypadku innych.

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

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

Mówiąc dokładniej, ocena przekazywana jest do innych poleceń poprzez status wyjścia. Niektóre programy mogą zdecydować o wyprowadzeniu statusu wyjścia w celu oznaczenia różnego rodzaju zdarzeń - pomyślne zakończenie programu, błąd określonego typu występujący podczas wykonywania lub błędy składniowe. W przypadku testpolecenia istnieją 0znaki prawdziwe i 1oznaczają fałsz. Jak zauważył Stephan, błędy składniowe dają status wyjścia 2.

Jego lokalizacja zależy od twojego systemu, a także wyjaśnia, dlaczego nie widziałeś strony podręcznika użytkownika man [. Na przykład na FreeBSD jest poniżej /bin. W systemie Linux (lub w moim szczególnym przypadku Ubuntu 16.04) jest on dostępny /usr/bin/. Jeśli to zrobisz man [lub man testw systemie Linux, zobaczysz tę samą dokumentację otwartą. Ważne jest również, aby pamiętać, że twoja powłoka może mieć własną implementację test.

Należy również zauważyć, że polecenie to ma problemy , które implementacja powłoki Korna (powszechnie znana jako odwołanie do „wyrażenia warunkowego” z podwójnymi nawiasami kwadratowymi [[ "$USER" = "root" ]]) ma na celu rozwiązanie. Ta funkcja jest również używana przez inne powłoki, takie jak bashi zsh.

Sergiy Kolodyazhnyy
źródło
/usr/bin/także dla Amazon Linux.
franklinsijo
@ StéphaneChazelas Dziękujemy. Odpowiedź odpowiednio zredagowana
Sergiy Kolodyazhnyy
3

Ani man [nie [ --helpdziała

W niektórych dystrybucjach (np. Ubuntu) man [następuje dowiązanie symboliczne do test(1). W przypadku innych (np. Arch) tak nie jest. (Ale teststrona man również dokumentuje użycie [)


type -a [ pokazuje, że zarówno wbudowana jest powłoka, jak i plik wykonywalny.

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

Wbudowany bash [ --helppo prostu drukuje komunikat o błędzie. (Ale ponieważ jest to wbudowane narzędzie, możesz użyć help [lub spojrzeć na stronę / dokumenty podręcznika bash).

/usr/bin/[ --help wypisuje wyjście pełnej pomocy (dla wersji GNU Coreutils), które zaczyna się od:

$ /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

a następnie opisuje dozwoloną składnię EXPRESSION.

Jest to kolejny sposób, w jaki mogłeś się tego dowiedzieć [i testsą one równoważne.


BTW, jeśli programujesz dla bash (lub interaktywnie piszesz jednowierszowe), polecam [[zamiast [. Jest lepiej na kilka sposobów, zobacz linki w odpowiedzi Serga.

Peter Cordes
źródło
2

[polecenie zwraca status wyjścia zero, jeśli wyrażenie zawarte w jego argumentach jest uważane za prawdziwe, a niezerowy status wyjścia, jeśli wyrażenie zawarte w jego argumentach jest uważane za fałszywe. Komunikat o błędzie również kończy się niepowodzeniem, jeśli jego ostatnim argumentem nie jest ](odbywa się to wyłącznie z powodów estetycznych).

Na przykład:

[ 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:" $?

… Wyświetli:

Status wyjścia [hello] wynosi: 0       - ponieważ niepusty łańcuch jest uważany za prawdziwy 
Status wyjścia [abc = abc] wynosi: 0   - ponieważ 'abc' naprawdę jest taki sam jak 'abc' 
Status wyjścia [] to : 1             - ponieważ pusty ciąg jest uważany za fałszywy 
Status wyjścia [abc = def] wynosi: 1   - ponieważ „abc” naprawdę różni się od „def”

Jednak bash i wiele innych powłok zazwyczaj nie wywołuje /bin/[(lub /usr/bin/[) w tych przypadkach, ale zamiast tego wywołuje wbudowane polecenie z dokładnie takim samym zachowaniem (wyłącznie ze względu na wydajność). Aby wywołać /bin/[(nie wbudowane surogate powłoki), musisz jawnie określić jego ścieżkę (np. /bin/[ hello ]Nie musisz poprzedzać prefiksem ]dirname ☺ ), lub skonfigurować powłokę, aby nie korzystała z wbudowanego surogatu (na przykład enable -n [w bash).

PS: Jak powiedziano w innych odpowiedziach, [jest to związane z test. Ale test, w przeciwieństwie [, nie wymaga ]jako ostatni argument (i nie oczekiwać, że w ogóle, dodając dodatkowy ]do testargumentów może spowodować, że nie z komunikatem o błędzie lub powrót złego rezultatu) . I można rozwiązać na tym samym pliku (na przykład jeden jest dowiązane ; w tym przypadku przekierowania zachowanie jest prawdopodobnie realizowane przez analizowanie obecnie zwany polecenia w / samego kodu) lub do innych plików. Ponieważ powłoka zwykle wywołuje również wbudowane zastępcze, chyba że ścieżka jest wyraźnie określona ( ) lub skonfigurowana tak, aby tego nie robić (/bin/test/bin/[test[test/bin/testenable -n test).

PPS: W przeciwieństwie do testi [, modern ifnigdy nie jest prawdziwym plikiem. Jest to część składni powłoki (np. Bash): if commandA; then commandB; fi(zamiast średników można użyć znaku nowej linii) powoduje, commandBże zostanie wykonany tylko wtedy, gdy zostanie commandAzakończony z zerowym statusem. To idealnie pasuje do zachowania testlub [, pozwalając łączyć je w podobny sposób if [ "$a" = foo ]; then …; fi (lub if test "$a" = foo; then …; fi- po prostu mniej czytelne) . Jednak współczesne skrypty często używają [[zamiast testlub [, który (jako if) nigdy nie jest prawdziwym plikiem, ale zawsze jest częścią składni powłoki.

PPPS: Jeśli chodzi o man- nigdy nie oczekuj, manże w każdym systemie plików będziesz mieć artykuł na temat każdej komendy. Informacje o niektórych (nawet „prawdziwe”, oparty na plikach) poleceń może brakować informacji o niektórych powłoki wbudowanych wtyczek może obecne nie tylko w artykule poświęconym konkretnej powłoce (to jest miejsce, gdzie na pewno znajdziemy informacje na temat test, [, if, [[). Mimo to wiele dystrybucji ma wyraźne manartykuły dla testi [. (O --help, nie jest rozpoznawany z testoczywistego powodu: musi cicho obsługiwać przypadki, takie jak a=--help; test "$a"; w niektórych dystrybucjach [ --help(bez zamykania ]) nadal pokazuje pomoc, w niektórych nie.)

Sasha
źródło
3
Zauważ, że ifbyło to polecenie do wersji Unix V6. Unix V7 (1979) przyszedł z powłoką Bourne'a (z jego if-then-else-fikonstrukcją) i nowym testpoleceniem.
Stéphane Chazelas