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?
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?
Réponses:
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 expression
et 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 [[-e
est considérée comme un mot shell. ksh
rechercherait une telle commande dans la liste des opérateurs intégrés et spéciaux (comme for
ou 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 -e
partie en [[-e
serait 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 ksh
développement reprendra ou qu'il semble y avoir un fork ou un clone (comme mksh
ou pdksh
), quelqu'un implémentera la syntaxe sans espace dans [[-e
.
[[
est appelé un "mot réservé" (voir la section 2.9 du langage de commande Shell ). Par définition POSIX, le mot réservé doit être délimité par des espaces. En revanche, (
est un opérateur, et la norme indique dans la section 2.9 "les représentations incluent l'espacement entre les jetons à certains endroits où <blank>
s ne serait pas nécessaire (lorsque l'un des jetons est un opérateur)". Voir la discussion connexe: Grammaire POSIX Shell: pourquoi Brace Group a besoin du premier espace alors que Subshell n'en a pas?char
est 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
.
i--<=++j
, et le compilateur n'a aucun problème à analyser cela comme i -- <= ++ j
.
_
). Ksh a (
comme opérateur et (echo hello)
analyse comme ( echo hello )
. Il a if
, {
, [[
et d' autres mots - clés , et ifx
, {x
et [[x
sont chacun un jeton - comme la façon dont charsomeletter
est l' un jeton C. En revanche, un non cité (x
dans 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 .
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 test
donnera 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
[
pas non plus de [[
commande, là. Le mot complet [[-e
est.if [[-e
fait un test vrai / faux. Existe-t-il donc une commande [[-e
? Est-ce parce que "[[-" "est ambigu?
Oui. Ou pas. [[-e
est ce que c'est: rien que le shell comprenne donc il suppose que c'est sa propre commande. ;-)
[[-e
est un nom de commande potentiellement valide (si bizarre).
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 .
ksh
shell dans la question. Bash emprunte l' [[
opérateur à ksh
et dans cette question, leur comportement est identique, mais je serais prudent avec les hypothèses car il y a des différences significatives entre ksh
et le bash
comportement 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
[[
règles intégrées. Je n'imaginais nullement qu'il ksh
s'agissait d'un obus dans lequel il shellcheck
pouvait trouver des erreurs. J'espère que d'autres apprécient ksh
et bash
sont 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.
[
c'est aussi un bash intégré :) manpages.ubuntu.com/manpages/bionic/man7/bash-builtins.7.html Mais vous n'êtes pas loin - [
ou test
vous 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é
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
[[
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, ksh
mais elle échouerait sur les systèmes avec externe, [[
donc pour des raisons de compatibilité, il est préférable de conserver l'espace requis.
Depuis [[-e
peut 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 e
inclusivement), 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.
[[
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