Por ejemplo, el siguiente comando no funciona:
if [[-e xyz]]; then echo File exists;fi
ksh da el siguiente error
[[-e: command not found
¿Es porque "[[-" es ambiguo?
Por ejemplo, el siguiente comando no funciona:
if [[-e xyz]]; then echo File exists;fi
ksh da el siguiente error
[[-e: command not found
¿Es porque "[[-" es ambiguo?
Respuestas:
La explicación más simple sería, ya que en el manual se presenta como [[ expression ]]
lo que tiene que haber espacio entre [[
y expression
y cierre ]]
. Pero, por supuesto, podemos intentar verlo más en profundidad. Los shells tienen una gramática algo compleja y dependen en gran medida del concepto de "división de palabras". En particular, el manual ksh (1) establece:
El shell comienza a analizar su entrada dividiéndola en palabras. Las palabras, que son secuencias de caracteres, están delimitadas por espacios en blanco sin comillas (espacio, tabulación y nueva línea) o metacaracteres (<,>, |,;, &, (y)). Además de delimitar palabras, los espacios y las pestañas se ignoran, mientras que las líneas nuevas suelen delimitar comandos.
Entonces, como se indica en el manual, la secuencia de caracteres [[-e
se considera una palabra shell. ksh
buscaría dicho comando en la lista de incorporados y operadores especiales (como for
o while
), luego buscaría un comando externo, y voilà, ninguno encontrado, por lo tanto, hay un mensaje de error sobre el comando no encontrado.
En este caso [[
tampoco son metacaracteres especiales. Si lo fueran, la -e
parte en [[-e
se consideraría una palabra shell, no un argumento en [[
sí mismo. Sin embargo, [[
se describe como comando compuesto, y el manual dice lo siguiente:
Los comandos compuestos se crean usando las siguientes palabras reservadas: estas palabras solo se reconocen si no se citan y si se usan como la primera palabra de un comando (es decir, no pueden ir precedidas de asignaciones de parámetros o redirecciones):
Por lo tanto, para [[
ser reconocido como un comando compuesto, debe ser la primera palabra de un comando o lista de comandos, lo que por definición previa de una "palabra" implica que debe estar separado por espacios, tabulaciones o líneas nuevas de otros palabras / argumentos.
Has preguntado en los comentarios : "¿Por qué el analizador no puede detenerse tan pronto como encuentra el patrón" [["y lo trata como el inicio de un comando condicional?" La respuesta corta probablemente se deba a que 1) influye en la [
sintaxis, ya que originalmente era un comando externo, y para el cumplimiento estándar POSIX existe como comando externo incluso hoy, y 2) porque el analizador de shell está construido de esta manera. El analizador de shell puede reconocer otros caracteres especiales no delimitados por espacios: echo $((2+2))
y (echo foobar)
funciona perfectamente bien. Tal vez en el futuro cuando se ksh
reanude el desarrollo o parezca haber una bifurcación o clon (como mksh
o pdksh
) alguien implementará una sintaxis sin espacio [[-e
.
[[
se denomina "palabra reservada" (consulte la sección 2.9 del lenguaje de comandos de Shell ). Por definición POSIX, la palabra reservada tiene que estar delimitada por espacios. Por el contrario, (
es un operador, y los estados estándar en la sección 2.9 "las representaciones incluyen el espacio entre los tokens en algunos lugares donde <blank>
s no sería necesario (cuando uno de los tokens es un operador)". Vea la discusión relacionada: Gramática de shell POSIX: ¿por qué Brace Group necesita el primer espacio pero Subshell no?char
es una palabra clave, pero aún no puede escribir charsomeletter = 'A';
y esperar que el analizador se detenga después de ver char
.
i--<=++j
, y el compilador no tiene problemas para analizar eso como i -- <= ++ j
.
_
). Ksh tiene (
como operador y (echo hello)
analiza como ( echo hello )
. Ha if
, {
, [[
, y otras palabras clave , y ifx
, {x
y [[x
son cada uno un token - como la forma charsomeletter
es una ficha C. En contraste, un sin comillas (x
en ksh son dos tokens, como cómo i--
son dos tokens en C. Lo que conceptualmente significa ser un operador difiere entre los shells de estilo Bourne (como ksh) y C. Pero Peter A. Schneider señaló un similitud léxica real .
Es importante tener en cuenta que [
es un comando, y la palabra clave de shell [[
en bash y ksh se basa en [
.
[[
se usa de manera similar a [
. A veces incluso se puede sustituir [
]
con [[
]]
sin cambio en el comportamiento. Con [
, como cualquier comando, un espacio es obligatorio entre el comando y sus argumentos. Lo mismo se aplica a [[
.
Solíamos tener solo /usr/bin/[
. Ahora la mayoría de los shells se han [
incorporado para la eficiencia, pero la sintaxis es la misma. En los depósitos que proporcionan [[
, funciona como una alternativa más versátil para [
.
Aquí está la descripción de [
en bash:
$ help [
[: [ arg... ]
Evaluate conditional expression.
This is a synonym for the "test" builtin, but the last argument must
be a literal `]', to match the opening `['.
Entonces [
es equivalente a test
(aparte de esperar un ]
argumento al final). help test
dará aún más detalles al respecto. Puedes comparar esto con help [[
.
También hay una página de manual para el comando externo [
( man \[
).
En el caso de
if [[-e
[
tampoco [[
es un comando, allí. La palabra completa [[-e
es.if [[-e
convierte en una prueba de verdadero / falso. Entonces , ¿ existe un comando [[-e
? ¿Es porque "[[-" es ambiguo?
Si. O no. [[-e
es lo que es: nada que el shell entienda, por lo que supone que es su propio comando. ;-)
[[-e
es un nombre de comando potencialmente válido (si se ve raro).
El espacio es un deliminador y es obligatorio. Como puedes ver en shellcheck
:
$ shellcheck gmail-browse-msgs-algorithm.sh
In gmail-browse-msgs-algorithm.sh line 847:
[[$Today != "${DaysArr[ i + DAY_DELETED_ON_NDX ]}" ]] && continue
^-- SC1035: You need a space after the [[ and before the ]].
(Tanto ksh como bash admiten [[
y no funcionan sin el espacio. Shellcheck proporciona exactamente esa salida con scripts ksh y bash similares que contienen esa línea con errores).
Por qué se necesitan delimitadores tiene que ver con tokens y léxicos .
ksh
shell en la pregunta. Bash toma prestado [[
operador ksh
y de esta tela de juicio su comportamiento es idéntico, pero me gustaría tener cuidado de supuestos ya que hay algunas diferencias significativas entre ksh
y bash
el comportamiento y el funcionamiento interno. Eso es solo porque shellcheck funciona en script bash, puede que no sea necesariamente una herramienta apropiada para scripts ksh. Solo algo a tener en cuenta al acercarse a diferentes proyectiles
[[
reglas integradas. De ninguna manera deduje que ksh
era un caparazón en el que shellcheck
podría encontrar errores. Espero que otros lo aprecien ksh
y bash
sean dos intérpretes diferentes. Gracias por mencionar eso. También vale la pena señalar que [[
es un bash incorporado, mientras que [
es un comando externo.
[
también es una función integrada en bash :) manpages.ubuntu.com/manpages/bionic/man7/bash-builtins.7.html Pero no está lejos, [
o test
debe ser un comando externo. En los días de Bourne Shell original [
era, de hecho, un comando externo, y todavía existe hoy en día /usr/bin/[
porque POSIX requiere que sea un comando externo pubs.opengroup.org/onlinepubs/009695399/utilities/test.html POSIX requiere muy pocos ser incorporado pubs.opengroup.org/onlinepubs/009695399/idx/sbi.html Builtin [
es para la eficiencia
ksh
; usar un hashbang o -s ksh
. Btw, ksh y bash se han [[
"incorporado", pero es una palabra clave , a diferencia de [
, que es un shell incorporado . (ksh :; whence -v [ [[
bash type [ [[
:) Los comandos internos y externos son sintácticamente similares. Una forma diferente [[
de esto [
es que [[
suprime algunas expansiones en sus argumentos, lo que no podría ser como un componente integrado, al igual {
que no podría agruparse si fuera un elemento integrado. Esta puede ser la razón por la cual {x
(o [[x
) ser una ficha se siente extraño. Creo que es correcto decir que las palabras clave y las palabras clave son léxicas pero no sintácticamente similares. @SergiyKolodyazhnyy
[[
puede ser un comando externo! Es decir, puede ser un programa y no una sintaxis compatible con su shell directamente. Sería posible soportar una sintaxis sin espacio, ksh
pero fallaría en sistemas con sistema externo, [[
por lo que por razones de compatibilidad es mejor mantener el espacio requerido.
BusyBox se proporciona [[
como un comando externo , por ejemplo.
Dado que [[-e
puede participar en la expansión de shell (se puede usar como
echo [[-e]*
para enumerar todos los archivos que comienzan con una letra entre [
e e
inclusive), sería un completo desastre si [
y si ]
los caracteres especiales no participaran en la división normal de palabras gobernada por espacios en blanco.
[[
es una palabra clave - presumiblemente árbol de análisis sintáctico de la cáscara requiere que las palabras clave deben ser delineadas por espacios en blanco