Come funziona esattamente "/ bin / ["?


50

Sono sempre sorpreso che nella cartella sia /binpresente un [programma.

È questo che viene chiamato quando stiamo facendo qualcosa del tipo if [ something ]:?

Chiamando [esplicitamente il programma in una shell, chiede un corrispondente ]e quando fornisco la parentesi di chiusura sembra non fare nulla, indipendentemente da ciò che inserisco tra parentesi.

Inutile dire che il solito modo di ottenere aiuto su un programma non funziona, cioè né man [[ --helpfunziona.


11
@IporSircer si [riferisce al testcomando, no expr, quindi dovrebbe essereman test
Sergiy Kolodyazhnyy,

8
man '['funziona bene per me - o hai dimenticato di citare [o hai una diversa definizione di "opere".
Toby Speight,

3
Alcuni avvertimenti: [valuta i suoi argomenti, quindi è necessario disporre di spazi tra tutti. [ a=b ]non è un confronto: sarà sempre vero (è una singola stringa: "a = b", che viene sempre valutata come vera ) E dovresti limitare il numero di argomenti a 4 (anche se le recenti implementazioni consentiranno di più .. Limitare a 4 lo rende più portabile, ad esempio: [ "a" = "b" ]ha già 4 argomenti: "a" "=" "b" e la fine non necessaria dell'argomento arg: "]"). Se hai bisogno di più: prove a catena con ad esempio:if [ "$Var_a" = "foo" ] && [ "$Var_b" = "bar" ] ; then : do something ; fi
Olivier Dulac l'

1
@OlivierDulac a !da solo (senza caratteri di escape e non quotati) non verrà sostituito, e lo sarebbe ancora di più if ! [ .... Tutte le espansioni bash che usano !includono almeno su altri personaggi
Muru,

3
Dovresti anche notare che c'è anche un [-builtin in bash(e forse anche altre shell) e che questo può essere usato al posto di /bin/[. Inoltre c'è il testcomando, che su molti sistemi è un collegamento simbolico a /bin/[(o viceversa) - ma su altri è un comando separato.
Baard Kopperud,

Risposte:


63

Il [compito del comando è valutare le espressioni di test. Ritorna con uno stato di uscita 0 (che significa vero ) quando l'espressione si risolve in vero e qualcos'altro (che significa falso ) altrimenti.

Non è che non faccia nulla, è solo che il suo risultato si trova nel suo stato di uscita. In una shell, puoi scoprire lo stato di uscita dell'ultimo comando $?per shell tipo Bourne o $statusnella maggior parte delle altre shell (fish / rc / es / csh / tcsh ...).

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

In altre lingue come perl, lo stato di uscita viene restituito, ad esempio, nel valore restituito di system():

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

Si noti che tutte le moderne shell tipo Bourne (e fish) hanno un [comando integrato . Quello in /bingenere verrebbe eseguito solo quando usi un'altra shell o quando fai cose come env [ foo = bar ]o find . -exec [ -f {} ] \; -printo quel perlcomando sopra ...

Il [comando è anche noto con il testnome. Quando viene chiamato come test, non richiede un ]argomento di chiusura .

Anche se il tuo sistema potrebbe non avere una pagina man per [, probabilmente ne ha una per test. Ma ancora una volta, nota che sarebbe documentare la /bin/[o /bin/testimplementazione. Per conoscere l' [integrato nella tua shell, dovresti invece leggere la documentazione per la tua shell.

Per ulteriori informazioni sulla cronologia di quell'utilità e sulla differenza con l' [[...]]espressione del test ksh, potresti dare un'occhiata a queste altre domande e risposte qui .


Bene, come al solito. Potresti voler aggiungere i commenti che ho aggiunto sotto la domanda di @Bregalad? o forse alcuni extra? In questo modo la risposta sarà ancora più completa su "come funziona esattamente" (noto che hai già dato informazioni più precise su "]" rispetto a me ^^)
Olivier Dulac,

"Tutte le conchiglie (e i pesci) simili a Bourne hanno un [comando" incorporato Questo è vero in pratica nel 21 ° secolo, ma sono abbastanza sicuro di averne usato uno senza [. Non ricordo se fosse una variante Bourne o una versione antica di cenere.
Gilles 'SO- smetti di essere malvagio' l'

@Gilles La shell Bourne ha implementato entrambi [e testcome builtin con Unix System III. Prima di ciò, non esisteva [ed testera solo un comando binario esterno.
jlliagre,

@Gilles, la cenere originale aveva incorporato il test (unito a expr), ma facoltativamente . Secondo in-ulm.de/~mascheck/various/ash , i BSD non hanno incorporato i test fino al 2000 circa. Ho aggiunto "moderno".
Stéphane Chazelas,

Perché nel mondo vorresti fare find . -exec [ f {} ] \; -print? Il comando find . -type f -printfarebbe la stessa cosa in modo molto più efficiente ...
Questo non è il mio vero nome il

41

Sono sempre sorpreso che nella cartella sia /binpresente un [programma.

Hai ragione di essere sorpreso. Questo è uno dei rari comandi POSIX, con l'utilità null ( :), che non rispetta la convenzione dei caratteri consentiti dal file comandi (set di caratteri del nome file portatile).

È quello che viene chiamato quando stiamo facendo qualcosa del tipo if [ something ]:?

Precisamente ma può essere utilizzato anche senza if.

Chiamando [esplicitamente il programma in una shell, chiede un corrispondente ]e quando fornisco la parentesi di chiusura sembra non fare nulla, indipendentemente da ciò che inserisco tra parentesi.

Non fa nulla di visibile ma in realtà fa la stessa cosa di quando viene utilizzato if, ovvero imposta lo stato di uscita su 0 (vero) o qualsiasi altra cosa (falso) a seconda di ciò che viene inserito tra parentesi. È (per una ragione) lo stesso comportamento del testcomando; l'unica differenza è che cerca il finale ]. Vedi man testper i dettagli.

Inutile dire che il solito modo di ottenere aiuto su un programma non funziona, cioè né man [[ --helpfunziona.

Dipende dal tuo sistema operativo. man [sicuramente funziona per me su un paio di distribuzioni Gnu / Linux tradizionali ma non su Solaris.

[ --helppotrebbe funzionare o meno a seconda dell'implementazione in quanto interrompe comunque la sintassi, mancando il finale ]. Inoltre, lo standard POSIX per il comando test/[ esclude esplicitamente tutte le opzioni, inclusa la --terminazione delle opzioni, quindi entrambe [ --help ]e test --helpdevono tornare truee tacere in base alla progettazione. Si noti che ciò che si mette all'interno delle parentesi o dopo [e che sembrano opzioni (ad esempio -f file, -n string, e simili) non sono opzioni , ma operandi .

Tutti i moderni interpreti Bourne shell stile (come bash, ksh, dashe zshsolo per citarne alcuni) attuare il test/ [utility internamente come incorporato in modo che quando li si utilizza, la pagina di manuale diritto di fare riferimento potrebbe essere quello del guscio, non testuno.

Prima di Unix System III (1981), la shell Bourne non implementava l' testutilità come incorporata, quindi era disponibile solo l'implementazione del comando binario esterno. Non esisteva un [comando (interno o incorporato) fino a Unix System III, quindi ad esempio con Unix Versione 7 dovevi digitare:

if test something ; then

invece di:

if [ something ] ; then

"man [sicuramente funziona per me nelle distribuzioni mainstream di Gnu / Linux" Hmm .. Centos (ammettiamo ancora 6.8) chiaramente non è abbastanza mainstream :) man testfunziona, ma d' man [ altra parte il mio ambiente cygwin non lo sa man [!
Adam,

1
@Adam Sì, hai ragione, è più recente di quanto pensassi anche se non ho scritto tutte le distribuzioni Linux tradizionali, solo che ha funzionato per me (cioè su quelle che ho testato). Questo è il clone OL 7.2 (RHEL 7.2) e Mint 17.1 (Ubuntu 14.04).
jlliagre,

man [non sembra funzionare su Manjaro (basato su Arch Linux). Il manuale per gli testelenchi [ --helpcome invocazione valida che dovrebbe mostrare aiuto, ma è interessante notare che non lo fa, e invece si lamenta di un mancante ], come con --version. L'aggiunta di ]non fa nulla, quindi sembra impossibile ottenere aiuto diverso da man test.
Darkhogg,

@Darkhogg Puoi provare /usr/bin/[ --helpo /bin/[ --help.
jlliagre,

1
@jlliagre Hai perfettamente ragione, stavo usando i builtin. env [ --helpoltre a /usr/bin/[ --helpfunzionare completamente bene (anche se ho bisogno di citare /usr/bin/[o zsh si lamenta).
Darkhogg,

10

[è in realtà più comunemente noto come testcomando. L'uso tipico di questo comando è semplicemente valutare le espressioni e restituire la loro condizione - vera o falsa. Viene spesso usato nelle if-then-else-fiistruzioni, sebbene possa essere usato al di fuori delle ifistruzioni per eseguire condizionalmente altri comandi tramite shell &&o ||operatori, in questo modo.

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

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

Più specificamente, la valutazione viene comunicata ad altri comandi tramite lo stato di uscita. Alcuni programmi possono scegliere di generare lo stato di uscita per indicare diversi tipi di eventi: il completamento del programma è corretto, si verifica un errore di tipo particolare durante l'esecuzione o errori di sintassi. Nel caso del testcomando, ci sono 0significa vero e 1significa falso. Come sottolineato da Stephan, gli errori di sintassi producono lo stato di uscita di 2.

La sua posizione dipende dal tuo sistema e spiega anche perché non hai visto la pagina man quando l'hai fatto man [. Ad esempio, su FreeBSD è sotto /bin. Su Linux (o nel mio caso particolare, Ubuntu 16.04) è presente /usr/bin/. Se lo fai man [o man testsu un sistema Linux, vedrai la stessa documentazione aperta. È anche importante notare che la shell potrebbe avere una propria implementazione di test.

Va anche notato che questo comando ha dei problemi , che l'implementazione della shell Korn (comunemente nota come riferimento "espressione condizionale" con parentesi quadre doppie [[ "$USER" = "root" ]]) cerca di risolvere. Questa funzione è utilizzata anche da altre shell come bashe zsh.


/usr/bin/anche per Amazon Linux.
Franklinsijo,

@ StéphaneChazelas Grazie. Risposta modificata di conseguenza
Sergiy Kolodyazhnyy l'

3

man [[ --helpopere

In alcune distro (ad esempio Ubuntu), man [segue un link simbolico a test(1). Su altri (ad esempio Arch), non è così. (Ma la testpagina man documenta anche l'uso di [)


type -a [ mostra che esiste sia una shell integrata che un eseguibile.

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

bash-builtin [ --helpstampa solo un messaggio di errore. (Ma dal momento che è un built-in, puoi usare help [o guardare la pagina man / docs di bash).

/usr/bin/[ --help stampa l'output della guida completa (per la versione GNU Coreutils), che inizia con:

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

e quindi descrive la sintassi consentita per EXPRESSION.

Questo è un altro modo in cui avresti potuto scoprirlo [e testsono equivalenti.


A proposito, se stai programmando per bash (o scrivendo una riga in modo interattivo), raccomanderei [[invece di [. È meglio in diversi modi, vedi i collegamenti nella risposta di Serg.


2

[il comando restituisce zero dello stato di uscita se espressione, contenuta nei suoi argomenti, è considerata vera e lo stato di uscita diverso da zero se espressione, contenuta nei suoi argomenti, è considerata falsa. Fallisce anche con un messaggio di errore se il suo ultimo argomento non lo è ](questo è fatto esclusivamente per motivi estetici).

Per esempio:

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

... produrrà:

Lo stato di uscita di [ciao] è: 0       - perché la stringa non vuota è considerata vera Lo 
stato di uscita di [abc = abc] è: 0   - perché 'abc' è davvero lo stesso di 'abc' Lo 
stato di uscita di [] è : 1             - poiché la stringa vuota è considerata falsa Lo 
stato di uscita di [abc = def] è: 1   - perché "abc" differisce in realtà da "def"

Tuttavia, bash e molte altre shell di solito in realtà non invocano /bin/[(o /usr/bin/[) in questi casi, ma chiamano invece il comando integrato con lo stesso comportamento (puramente per motivi di prestazioni). Per invocare /bin/[(non surrogato incorporato della shell) è necessario specificare esplicitamente il suo percorso (ad esempio /bin/[ hello ]; non è necessario ]aggiungere un prefisso con dirname anche se ☺ ) o configurare la shell per non utilizzare un surrogato incorporato (ad esempio, enable -n [in bash).

PS: Come è stato detto in altre risposte, [è correlato test. Ma test, a differenza [, non richiede ]come ultimo argomento (e non se lo aspetta affatto; l'aggiunta di extra ]agli testargomenti può causare il fallimento con un messaggio di errore o la restituzione di risultati errati) . L' /bin/teste /bin/[può risolversi nello stesso file (ad es. Uno è simbolicamente collegato ; in questo caso la deviazione del comportamento è probabilmente implementata analizzando il comando attualmente chiamato all'interno del test/ [code stesso) o in file diversi. Infatti test, la shell di solito invoca anche surrogato incorporato, a meno che path non sia esplicitamente specificato ( /bin/test) o sia configurato per non farlo (enable -n test).

PPS: A differenza di teste [, il moderno ifnon è mai un vero file. Fa parte della sintassi della shell (ad es. Bash): if commandA; then commandB; fi(le nuove righe possono essere usate al posto dei punti e virgola) fa sì commandBche venga eseguita if-and-only-se commandAesce con stato zero. Questo si adatta perfettamente al comportamento di testo [, consentendo di combinarli come if [ "$a" = foo ]; then …; fi (o if test "$a" = foo; then …; fi- solo meno leggibili) . Tuttavia, gli script moderni usano spesso [[invece di testo [, che (come il if) non è mai un file reale, ma fa sempre parte della sintassi della shell.

PPPS: Per quanto riguarda man- non aspettarti mai mandi avere un articolo su ogni comando nel tuo file system. Informazioni su alcune informazioni (anche "reale", basato su file) i comandi potrebbero mancare, in alcune shell built-in forse presente non solo all'interno di un articolo dedicato alla shell specifico (che è il luogo dove si sicuramente troverete informazioni test, [, if, [[). Tuttavia, molte distribuzioni hanno articoli espliciti manper teste [. (A proposito --help, non è riconosciuto testper ovvi motivi: deve gestire casi silenziosi come a=--help; test "$a"; su alcune distribuzioni [ --help(senza chiusura ]) mostra ancora aiuto, su alcuni non lo fa.)


3
Si noti che ifera un comando fino a Unix V6. Unix V7 (1979) arrivò con la shell Bourne (con il suo if-then-else-ficostrutto) e il nuovo testcomando.
Stéphane Chazelas,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.