¿Cómo funciona exactamente "/ bin / ["?

50

Siempre me sorprende que en la carpeta /binhaya un [programa.

¿Es esto lo que se llama cuando estamos haciendo algo como if [ something ]:?

Al llamar al [programa explícitamente en un shell, solicita un correspondiente ], y cuando proporciono el corchete de cierre parece que no hace nada, sin importar lo que inserte entre los corchetes.

No hace falta decir que la forma habitual de obtener ayuda sobre un programa no funciona, es decir, man [ni [ --helpfunciona.

Bregalad
fuente
11
@IporSircer se [refiere al testcomando, no expr, así que debería serloman test
Sergiy Kolodyazhnyy
8
man '['funciona bien para mí, ya sea que olvidó citar [o tiene una definición diferente de "obras".
Toby Speight
3
Algunas advertencias: [evalúa sus argumentos, por lo que debe tener espacios entre todos ellos. [ a=b ]no es una comparación: siempre será verdadero (es una sola cadena: "a = b", que siempre se evalúa como verdadera ) Y debe limitar el número de argumentos a 4 (aunque las implementaciones recientes permitirán más ... . limitar a 4 lo hace más portátil. Por ejemplo: [ "a" = "b" ]ya tiene 4 argumentos: "a" "=" "b" y el final no necesario de la prueba arg: "]"). Si necesita más: pruebas de cadena con, por ejemplo:if [ "$Var_a" = "foo" ] && [ "$Var_b" = "bar" ] ; then : do something ; fi
Olivier Dulac
1
@OlivierDulac a !por sí mismo (sin escapes y sin comillas) no será reemplazado, y aún mejor sería if ! [ .... Todas las expansiones de bash que usan !incluyen al menos otros personajes
muru
3
También debe tener en cuenta que también hay un [-builtin en bash(y posiblemente también otros depósitos), y que se puede usar en lugar de /bin/[. También está el testcomando, que en muchos sistemas es un enlace simbólico /bin/[(o viceversa), pero en otros es un comando separado.
Baard Kopperud

Respuestas:

63

El [trabajo del comando es evaluar las expresiones de prueba. Regresa con un estado de salida 0 (que significa verdadero ) cuando la expresión se resuelve en verdadero y otra cosa (que significa falso ) de lo contrario.

No es que no haga nada, es solo que su resultado se encuentra en su estado de salida. En un shell, puede averiguar sobre el estado de salida del último comando en los $?shells tipo Bourne o $statusen la mayoría de los otros shells (fish / rc / es / csh / tcsh ...).

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

En otros idiomas como perl, el estado de salida se devuelve, por ejemplo, en el valor de retorno de system():

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

Tenga en cuenta que todos los shells modernos tipo Bourne (y fish) tienen un [comando incorporado . La de /binque por lo general sólo se ejecutará cuando se utiliza otro shell o cuando haces cosas como env [ foo = bar ]o find . -exec [ -f {} ] \; -printo que perlcomando anterior ...

El [comando también se conoce por el testnombre. Cuando se llama como test, no requiere un ]argumento de cierre .

Si bien es posible que su sistema no tenga una página de manual [, probablemente tenga una para test. Pero nuevamente, tenga en cuenta que documentaría la implementación /bin/[o /bin/test. Para saber acerca de la [construcción en su shell, debe leer la documentación de su shell.

Para obtener más información sobre el historial de esa utilidad y la diferencia con la [[...]]expresión de prueba ksh, es posible que desee echar un vistazo a estas otras preguntas y respuestas aquí .

Stéphane Chazelas
fuente
Bien como siempre. ¿Es posible que desee agregar los comentarios que agregué debajo de la pregunta @Bregalad? o tal vez algunos extra? De esa manera, la respuesta será aún más completa sobre "cómo funciona exactamente" (noto que ya dio una información más precisa sobre "]" que yo ^^)
Olivier Dulac
“Todas las conchas (y peces) similares a Bourne tienen un [comando” incorporado [. No recuerdo si era una variante de Bourne o una versión antigua de ceniza.
Gilles 'SO- deja de ser malvado'
@Gilles El Bourne shell implementado tanto [y testcomo builtins con Unix System III. Antes de eso, no había [y testsolo había un comando binario externo.
jlliagre
@Gilles, la ceniza original tenía una prueba incorporada (fusionada con expr), pero opcionalmente . Según in-ulm.de/~mascheck/various/ash , los BSD no tenían pruebas integradas hasta alrededor del año 2000. He agregado "moderno".
Stéphane Chazelas
¿Por qué demonios te gustaría hacer find . -exec [ f {} ] \; -print? El comando find . -type f -printharía lo mismo de manera mucho más eficiente ...
Este no es mi nombre real el
41

Siempre me sorprende que en la carpeta /binhaya un [programa.

Tienes razón en sorprenderte. Ese es uno de los raros comandos POSIX, con la utilidad nula ( :), que no respeta la convención de caracteres permitidos del archivo de comandos (juego de caracteres de nombre de archivo portátil).

¿Es lo que se llama cuando hacemos algo como if [ something ]:?

Precisamente, pero se puede usar sin el iftambién.

Al llamar al [programa explícitamente en un shell, solicita un correspondiente ], y cuando proporciono el corchete de cierre parece que no hace nada, sin importar lo que inserte entre los corchetes.

No hace nada visible, pero en realidad hace lo mismo que cuando se usa if, es decir, establece el estado de salida en 0 (verdadero) o cualquier otra cosa (falso) dependiendo de lo que ponga dentro de los corchetes. Es (por una razón) el mismo comportamiento que el testcomando; La única diferencia es que busca el final ]. Ver man testpara más detalles.

No hace falta decir que la forma habitual de obtener ayuda sobre un programa no funciona, es decir, man [ni [ --helpfunciona.

Eso depende de su sistema operativo. man [definitivamente funciona para mí en un par de distribuciones principales de Gnu / Linux, pero no funciona en Solaris.

[ --helppodría funcionar o no dependiendo de la implementación ya que de todos modos está rompiendo la sintaxis, perdiendo el final ]. Por otra parte, el estándar POSIX para el test/ [comando excluye explícitamente todas las opciones, incluyendo la --opción de terminación por lo tanto [ --help ]y test --helpnecesidad de volver truey estar en silencio por diseño. Tenga en cuenta que lo que se pone dentro de los corchetes o después [y que se parecen a las opciones (por ejemplo -f file, -n string, y los gustos) no son opciones pero operandos .

Todos los modernos intérpretes de concha estilo Bourne (como bash, ksh, dashy zshpara nombrar unos pocos) implementan el test/ [utilidad internamente como una orden interna de modo que cuando usted los usa, la página Man adecuada para referirse a que podría ser la una de la cáscara, no el testuno.

Antes de Unix System III (1981), el shell Bourne no implementaba la testutilidad como incorporada, por lo que solo estaba disponible la implementación del comando binario externo. No había un [comando (interno o integrado) hasta Unix System III, por lo que, por ejemplo, en la Versión 7 de Unix, tenía que escribir:

if test something ; then

en lugar de:

if [ something ] ; then
jlliagre
fuente
"man [definitivamente funciona para mí en distribuciones Gnu / Linux convencionales" Hmm .. Centos (ciertamente 6.8 todavía) claramente no es lo suficientemente convencional :) man testfunciona pero no ¡ man [ Por otro lado, mi entorno cygwin sí lo sabe man [!
Adam
1
@ Adam Sí, tienes razón, eso es más reciente de lo que pensaba, aunque no escribí todas las distribuciones de Linux convencionales, solo que funcionó para mí (es decir, en las que probé). Es el clon OL 7.2 (RHEL 7.2) y Mint 17.1 (Ubuntu 14.04).
jlliagre
man [no parece funcionar en Manjaro (basado en Arch Linux). El manual de testlistas [ --helpcomo una invocación válida que debería mostrar ayuda, pero curiosamente no lo hace, y en cambio se queja de una falta ], al igual que con --version. Agregar el ]no hace nada, por lo que parece imposible obtener ayuda que no sea de man test.
Darkhogg
@Darkhogg Puedes probar /usr/bin/[ --helpo /bin/[ --help.
jlliagre
1
@jlliagre Tienes toda la razón, estaba usando los builtins. env [ --helpasí como /usr/bin/[ --helptrabajar completamente bien (aunque necesito citar /usr/bin/[o zsh se queja).
Darkhogg
10

[en realidad se conoce más comúnmente como testcomando. El uso típico de este comando es simplemente evaluar expresiones y devolver su condición, verdadera o falsa. A menudo se usa en if-then-else-fideclaraciones, aunque se puede usar fuera de las ifdeclaraciones para ejecutar condicionalmente otros comandos a través de shell &&u ||operadores, por ejemplo.

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

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

Más específicamente, la evaluación se comunica a otros comandos a través del estado de salida. Algunos programas pueden optar por mostrar el estado de salida para indicar diferentes tipos de eventos: el programa se completa con éxito, se produce un error de tipo particular durante la ejecución o errores de sintaxis. En el caso del testcomando, hay 0significa verdadero y 1significa falso. Como señaló Stephan, los errores de sintaxis producen el estado de salida de 2.

Su ubicación depende de su sistema, y ​​también explica por qué no vio la página de manual cuando lo hizo man [. Por ejemplo, en FreeBSD está debajo /bin. En Linux (o en mi caso particular, Ubuntu 16.04) está en /usr/bin/. Si lo hace man [o man testen un sistema Linux, verá la misma documentación abierta. También es importante tener en cuenta que su shell puede tener su propia implementación de test.

También debe tenerse en cuenta que este comando tiene problemas que la implementación de Korn Shell (comúnmente conocida como referencia de "expresión condicional" con corchetes dobles [[ "$USER" = "root" ]]) busca resolver. Esta característica también es utilizada por otros shells como bashy zsh.

Sergiy Kolodyazhnyy
fuente
/usr/bin/para Amazon Linux también.
franklinsijo
@ StéphaneChazelas Gracias. Respuesta editada en consecuencia
Sergiy Kolodyazhnyy
3

Ni man [ni [ --helpfunciona

En algunas distribuciones (por ejemplo, Ubuntu), man [sigue un enlace simbólico a test(1). En otros (por ejemplo, Arch), este no es el caso. (Pero la testpágina del manual también documenta el uso [)


type -a [ le muestra que hay un shell integrado y un ejecutable.

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

bash-builtin [ --helpsolo imprime un mensaje de error. (Pero como es una función integrada, puede usar help [o mirar la página / documentos de bash man).

/usr/bin/[ --help imprime la salida de ayuda completa (para la versión GNU Coreutils), que comienza 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

y luego describe la sintaxis permitida para EXPRESSION.

Esta es otra forma en que podría haber descubierto eso [y testson equivalentes.


Por cierto, si está programando para bash (o escribiendo frases interactivas), recomendaría en [[lugar de hacerlo [. Es mejor de varias maneras, vea los enlaces en la respuesta de Serg.

Peter Cordes
fuente
2

[El comando devuelve el estado de salida cero si la expresión, contenida en sus argumentos, se considera verdadera y el estado de salida distinto de cero si la expresión, contenida en sus argumentos, se considera falsa. También falla con el mensaje de error si su último argumento no lo es ](esto se hace únicamente por razones estéticas).

P.ej:

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

... dará salida:

El estado de salida de [hola] es: 0       - porque la cadena no vacía se considera verdadera 
El estado de salida de [abc = abc] es: 0   - porque 'abc' realmente es lo mismo que 'abc' 
El estado de salida de [] es : 1             - porque la cadena vacía se considera falsa 
El estado de salida de [abc = def] es: 1   - porque 'abc' realmente difiere de 'def'

Sin embargo, bash y muchos otros shells generalmente no invocan /bin/[(o /usr/bin/[) en estos casos, sino que llaman al comando incorporado con exactamente el mismo comportamiento (solo por razones de rendimiento). Para invocar /bin/[(no el sustituto incorporado del shell) debe especificar explícitamente su ruta (p /bin/[ hello ].] Ej ., No necesita prefijar con dirname aunque ☺ ), o configurar el shell para que no use un sustituto incorporado (por ejemplo, enable -n [en bash).

PD: Como se dijo en otras respuestas, [está relacionado con test. Pero test, a diferencia [, no requiere ]como último argumento (y no lo espera en absoluto; agregar más ]a los testargumentos puede hacer que falle con un mensaje de error o que devuelva un resultado incorrecto) . El /bin/testy /bin/[puede resolverse en el mismo archivo (p. Ej., Uno está enlazado a un enlace simbólico ; en este caso, el desvío de comportamiento probablemente se implementa analizando el comando actualmente llamado dentro del propio código test/ [) o en diferentes archivos. Para test, el shell también generalmente invoca un sustituto incorporado, a menos que la ruta se especifique explícitamente ( /bin/test) o esté configurada para no hacerlo (enable -n test)

PPS: a diferencia de testy [, moderno ifnunca es un archivo real. Es parte de la sintaxis de shell (por ejemplo, bash): if commandA; then commandB; fi(se pueden usar nuevas líneas en lugar de punto y coma) hace commandBque se ejecute si y solo si commandAsale con estado cero. Esto se adapta perfectamente al comportamiento de testo [, lo que permite combinarlos como if [ "$a" = foo ]; then …; fi (o if test "$a" = foo; then …; fi, simplemente, menos legibles) . Sin embargo, los scripts modernos a menudo usan en [[lugar de testo [, que (como el if) nunca es un archivo real, sino que siempre es parte de la sintaxis de shell.

PPPS: En cuanto a man, nunca espere mantener un artículo sobre cada comando en su sistema de archivos. Información sobre algo de información (incluso "real", basada en archivos) comandos pueden faltar, en algunos shell empotrados puede estar presente no sólo en un artículo dedicado a la cáscara específica (que es el lugar en el que sin duda encontrará información sobre test, [, if, [[). Aún así, muchas distribuciones tienen artículos explícitos manpara testy [. (Acerca de --help, no se reconoce testpor razones obvias: necesita manejar en silencio casos como a=--help; test "$a"; en algunas distribuciones [ --help(sin cerrar ]) todavía muestra ayuda, en algunos no lo hace).

Sasha
fuente
3
Tenga en cuenta que ifera un comando hasta Unix V6. Unix V7 (1979) vino con el shell Bourne (con su if-then-else-ficonstrucción) y el nuevo testcomando.
Stéphane Chazelas