Pourquoi un espace vide est-il requis entre "[[" et "-e xxx" dans ksh?

9

Par exemple, la commande suivante ne fonctionne pas:

if [[-e xyz]]; then echo File exists;fi

ksh donne l'erreur suivante

[[-e: command not found

Est-ce parce que "[[-" "est ambigu?

AcBap
la source
2
[[est un mot - clé - vraisemblablement l'arbre d'analyse du shell nécessite que les mots-clés soient délimités par des espaces
steeldriver
Une autre façon de voir les choses est probablement que vous pourriez écrire une fonction [[-, comment le shell saurait-il analyser "faire le drapeau e sur [[" au lieu de "faire la fonction [[- sur e").
pbhj

Réponses:

15

L'explication la plus simple serait, car dans le manuel, elle apparaît comme [[ expression ]]telle qu'il doit y avoir un espace entre [[et expressionet la fermeture ]]. Mais bien sûr, nous pouvons essayer de l'examiner plus en profondeur. Les coquilles ont une grammaire quelque peu complexe et reposent fortement sur le concept de "division de mots". En particulier, le manuel ksh (1) indique:

Le shell commence à analyser son entrée en la décomposant en mots. Les mots, qui sont des séquences de caractères, sont délimités par des espaces blancs sans guillemets (espace, tabulation et nouvelle ligne) ou des méta-caractères (<,>, |,;, &, (et)). Mis à part la délimitation des mots, les espaces et les tabulations sont ignorés, tandis que les retours à la ligne délimitent généralement les commandes.

Ainsi, comme indiqué dans le manuel, la séquence de caractères [[-eest considérée comme un mot shell. kshrechercherait une telle commande dans la liste des opérateurs intégrés et spéciaux (comme forou while), puis rechercherait une commande externe - et voilà - aucune trouvée, donc il y a un message d'erreur sur la commande introuvable.

Dans ce cas, ce [[ne sont pas non plus des méta-caractères spéciaux. S'ils l'étaient, la -epartie en [[-eserait considérée comme un mot shell, et non comme un argument en [[soi. Cependant, elle [[est décrite comme une commande composée et le manuel dit ce qui suit:

Les commandes composées sont créées à l'aide des mots réservés suivants - ces mots ne sont reconnus que s'ils ne sont pas entre guillemets et s'ils sont utilisés comme premier mot d'une commande (c'est-à-dire qu'ils ne peuvent pas être précédés d'affectations de paramètres ou de redirections):

Ainsi, pour [[être reconnu comme une commande composée, il doit s'agir du premier mot d'une commande ou d'une liste de commandes, ce qui, selon la définition précédente d'un "mot", implique qu'il doit être séparé par des espaces, des tabulations ou des nouvelles lignes des autres mots / arguments.


Vous avez demandé dans les commentaires : "Pourquoi l'analyseur ne peut-il pas s'arrêter dès qu'il trouve" [["modèle, et le traite comme le début d'une commande conditionnelle?" La réponse courte est probablement parce que 1) l'influence de la [syntaxe, car il s'agissait à l'origine d'une commande externe, et pour la norme POSIX, la conformité existe encore aujourd'hui en tant que commande externe, et 2) parce que l'analyseur shell est construit de cette manière. L'analyseur de shell peut reconnaître d'autres caractères spéciaux non délimités par l'espace: echo $((2+2))et (echo foobar)fonctionne parfaitement bien. Peut-être qu'à l'avenir, lorsque le kshdéveloppement reprendra ou qu'il semble y avoir un fork ou un clone (comme mkshou pdksh), quelqu'un implémentera la syntaxe sans espace dans [[-e.

Voir également:

Sergiy Kolodyazhnyy
la source
3
Je pense que la citation manuelle de ksh est vraiment sur place. Il est similaire à tout autre langage de programmation: en C, charest un mot-clé mais vous ne pouvez toujours pas écrire charsomeletter = 'A';et vous attendre à ce que l'analyseur s'arrête après avoir vu char.
Peter - Rétablir Monica le
Je pense que la principale différence entre votre exemple de "char" et le symbole "[[" dans la question est qu'un identifiant alphanumérique, en général, a besoin d'un délimiteur d'espace pour se séparer des autres; les symboles spéciaux comme jetons, en revanche, n'ont pas besoin de délimiteurs d'espace.
AcBap
Exactement. Je ne suis pas sûr que la comparaison avec C soit utile. En C, on peut dire i--<=++j, et le compilateur n'a aucun problème à analyser cela comme i -- <= ++ j.
Scott
@Scott Je pense que la comparaison C est utile (et que c'est en quelque sorte secondaire que les identificateurs C n'autorisent que les caractères alphanumériques et _). Ksh a (comme opérateur et (echo hello)analyse comme ( echo hello ). Il a if, {, [[et d' autres mots - clés , et ifx, {xet [[xsont chacun un jeton - comme la façon dont charsomeletterest l' un jeton C. En revanche, un non cité (xdans ksh est deux jetons - comme i--c'est le cas pour deux jetons en C. Ce que cela signifie même conceptuellement d'être un opérateur diffère entre les coquilles de style Bourne (comme ksh) et C. réelle similitude lexicale .
Eliah Kagan
2

Ce qui est important à noter, c'est qu'il [s'agit d'une commande, et le mot clé shell [[dans bash et ksh est basé sur [.

[[est utilisé de manière similaire à [. Parfois , vous pouvez même remplacer [ ]avec [[ ]]sans changement de comportement. Avec [, comme toute commande, un espace est obligatoire entre la commande et ses arguments. La même chose s'applique à [[.

Nous en avions seulement /usr/bin/[. Maintenant, la plupart des shells sont [intégrés pour plus d'efficacité, mais la syntaxe est la même. Dans les coquilles qui le fournissent [[, il fonctionne comme une alternative plus polyvalente à [.

Voici la description de [in 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 `['.

[Est donc équivalent à test(à part attendre un ]argument à la toute fin). help testdonnera encore plus de détails à ce sujet. Vous pouvez comparer cela à help [[.

Il existe également une page de manuel pour la commande externe [( man \[).

Dans le cas de

if [[-e
  • Il n'y a [pas non plus de [[commande, là. Le mot complet [[-eest.
  • Le if [[-efait un test vrai / faux. Existe-t-il donc une commande [[-e?

Est-ce parce que "[[-" "est ambigu?

Oui. Ou pas. [[-eest ce que c'est: rien que le shell comprenne donc il suppose que c'est sa propre commande. ;-)

Rinzwind
la source
"% help [[" dit que "[[" est une commande conditionnelle. Pourquoi l'analyseur ne peut-il pas s'arrêter dès qu'il trouve le motif "[[" et le traite comme le début d'une commande conditionnelle?
AcBap
@Myloti [[-eest un nom de commande potentiellement valide (si bizarre).
Gordon Davisson
2

L'espace est un délimiteur et est requis. Comme vous pouvez le voir sur 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 ]].

(Les deux ksh et bash prennent en charge [[et ne fonctionnent pas sans l'espace. Shellcheck donne exactement cette sortie avec des scripts ksh et bash similaires contenant cette ligne de bogue.)

La raison pour laquelle les suppresseurs sont nécessaires est liée aux jetons et aux lexiques .

WinEunuuchs2Unix
la source
Veuillez noter que OP a posé des questions sur le kshshell dans la question. Bash emprunte l' [[opérateur à kshet dans cette question, leur comportement est identique, mais je serais prudent avec les hypothèses car il y a des différences significatives entre kshet le bashcomportement et les internes. C'est juste parce que shellcheck fonctionne sur le script bash, ce n'est peut-être pas nécessairement l'outil approprié pour les scripts ksh. Juste quelque chose à garder à l'esprit lors de l'approche de différents obus
Sergiy Kolodyazhnyy
@SergiyKolodyazhnyy J'étais opportuniste en utilisant shellcheck pour mettre en évidence les [[règles intégrées. Je n'imaginais nullement qu'il kshs'agissait d'un obus dans lequel il shellcheckpouvait trouver des erreurs. J'espère que d'autres apprécient kshet bashsont deux interprètes différents. Merci d'avoir mentionné cela. Il convient également de noter [[un bash intégré alors qu'il [s'agit d'une commande externe.
WinEunuuchs2Unix
En fait, [c'est aussi un bash intégré :) manpages.ubuntu.com/manpages/bionic/man7/bash-builtins.7.html Mais vous n'êtes pas loin - [ou testvous devez être une commande externe. Au temps du Bourne shell d'origine [était en fait une commande externe, et existe toujours de nos jours /usr/bin/[car POSIX exige qu'il s'agisse d'une commande externe pubs.opengroup.org/onlinepubs/009695399/utilities/test.html Très peu sont requis par POSIX pour être intégré pubs.opengroup.org/onlinepubs/009695399/idx/sbi.html L'intégration[ est pour l'efficacité
Sergiy Kolodyazhnyy
2
Shellcheck sait ksh; utilisez un hashbang ou -s ksh. Btw, ksh et bash ont [["intégré", mais c'est un mot - clé , contrairement [, qui est un shell intégré . (ksh :; whence -v [ [[bash type [ [[:) Les commandes internes et externes sont syntaxiquement similaires. Une façon [[diffère de [celle qui [[supprime certaines extensions dans ses arguments, ce qu'elle ne pourrait pas en tant que module intégré - tout comme {le regroupement ne pouvait pas être un module intégré. C'est peut-être pourquoi {x(ou [[x) être un jeton semble étrange. Je pense qu'il est juste de dire que les commandes internes et les mots clés sont lexicalement mais pas syntaxiquement similaires. @SergiyKolodyazhnyy
Eliah Kagan
1
@EliahKagan En fait, j'ai posté une question sur U&L pour obtenir une réponse précise sur ce que POSIX pense de cette situation unix.stackexchange.com/questions/526574/… Le langage shell est suffisamment complexe, donc j'espère que quelqu'un pourra l'expliquer en termes plus formels
Sergiy Kolodyazhnyy
1

[[peut être une commande externe! Autrement dit, il peut s'agir d'un programme et non d'une syntaxe directement prise en charge par votre shell. La prise en charge d'une syntaxe sans espace serait possible, kshmais elle échouerait sur les systèmes avec externe, [[donc pour des raisons de compatibilité, il est préférable de conserver l'espace requis.

BusyBox fournit par [[exemple une commande externe .

DarkDust
la source
0

Depuis [[-epeut participer à l'expansion du shell (il peut être utilisé comme

echo [[-e]*

afin de répertorier tous les fichiers commençant par une lettre entre [et einclusivement), ce serait un gâchis complet si [et si ]des caractères spéciaux ne participaient pas à la division normale des mots régie par des espaces.


la source