Forum Programmation.shell Shell Parameter Expansion

Posté par  . Licence CC By‑SA.
Étiquettes : aucune
1
20
mar.
2024

Bonjour||soir.

Je comprends pas les syntaxes suivantes.
Extrait de la documentation bash : https://www.gnu.org/software/bash/manual/bash.html (3.5.3 Shell Parameter Expansion)

Put another way, if the colon is included, the operator tests for both parameter’s existence and that its value is not null; if the colon is omitted, the operator tests only for existence.

${parameter:-word}
If parameter is unset or null, the expansion of word is substituted. Otherwise, the value of parameter is substituted.

# v=123
# echo ${v-unset}
123

${parameter:=word}
If parameter is unset or null, the expansion of word is assigned to parameter. The value of parameter is then substituted. Positional parameters and special parameters may not be assigned to in this way.

# var=
# : ${var:=DEFAULT}
# echo $var
DEFAULT

Bon déjà pour le premier paragraphe. Si ":" est là le test est "existe et n'est pas nul" sinon c'est uniquement "si existe". Ca ok.

Par contre je ne comprends pas la différence entre les deux syntaxes, en gros la partie "Positional parameters and special parameters may not be assigned to in this way."

1) Concernant l'aspect langue (linguistique). Je reconnais que mon anglais est ce qu'il est mais:
- Je ne comprend pas l’emploi du mot "parameter", cela ne devrait pas être "variable" ?
- même chose pour "expansion", "replace" ou quelque chose comme cela ne serait pas mieux ?

2) "If parameter is unset or null, the expansion of word is assigned to parameter. The value of parameter is then substituted." traduit en français donne pour moi (après avoir fait des tests):

Si la variable n'existe pas ou n'a pas de valeur renseignée, celle-ci est créé avec word en valeur. Sinon … on garde la valeur de la variable précédemment affectée.

# echo ${qsd-unmot}
unmot
# tata=unevaleur
# echo ${qsd-unmot}
unevaleur
# vartest=
# : ${vartest:=DEFAULT}
# echo $vartest
DEFAULT
# vartest=uneautrevaleur
# : ${vartest:=DEFAULT}
# echo $vartest
uneautrevaleur

Je vois pas de différence.

3) à quoi sert le premier : dans : ${vartest:=DEFAULT} ? Et qu'est ce ?
C'est vraisemblablement pas une commande bien que avec mon zsh configuré pour que le mot passe en vert si la commande existe (même principe que avec fish); ":" est en vert.
Par contre man : ou : -h --help ne fonctionne pas :)


Pour donner un contexte à cette interrogation, j'étais en train de fouiner les fichierspoints (aka dotfiles) présent sur l'Internet dans le but de mettre à jours les miens.
Or je suis "tombé" sur les deux syntaxes suivantes dans des fichiers .profile .bash_profile .zsh_profile et je ne comprends pas qu'elles sont les différences.

export XDG_CONFIG_HOME="${XDG_CONFIG_HOME:-$HOME/.config}"
export XDG_CONFIG_HOME=${XDG_CONFIG_HOME:="$HOME/.config"}

Et c'est aussi la valse des " ! et pour certain la partie de cache cache des export.
Vu qu'il s'agit de variable d'environnement je mettrais export et je serais plutôt d'avis d'utiliser "${}" bien que pour le coups je vois pas trop ce que ça change.

  • # Éléments de réponse

    Posté par  (site web personnel) . Évalué à 7 (+5/-0).

    1) Les détails linguistiques sont donnés dans le premier paragraphe de « 3.4 Shell Parameters », non ? Cf. également POSIX, qui utilise le même vocabulaire.

    2) C'est incomplet, on ne fait pas que modifier au besoin la variable en question. La valeur est également remplacée. Tu peux t'en convaincre en remplaçant : par echo.

    Quant à :, à l'extérieur des accolades, c'est un no-op, cf. bash-builtins(7) :

           : [arguments]
                  No effect; the command does nothing beyond expanding arguments and performing  any  specified  redirec‐
                  tions.  The return status is zero.
    

    3) À l'intérieur des accolades, il ne s'agit pas d'un : unitaire, mais de :-, :=, :+, etc., il s'agit donc d'une partie d'un séparateur entre la variable à gauche et des trucs plus sophistiqués à droite. Bien évidemment, le fait que dans l'exemple donné pour :-, la syntaxe utilisée est… celle d'une autre opération n'aide pas.

    Le tableau côté POSIX donne les subtilités, mais en résumé pour ces deux opérations :

    kibi@tokyo:~$ a=; echo ${a-123}
    
    kibi@tokyo:~$ unset a; echo ${a-123}
    123
    

    vs.

    kibi@tokyo:~$ a=; echo ${a:-123}
    123
    kibi@tokyo:~$ unset a; echo ${a-123}
    123
    

    Je ne pense pas qu'il y ait de différences fondamentales entre les deux syntaxes d'export… Jouons avec deux variables au lieu d'une :

    kibi@tokyo:~$ unset A; unset B; export A=${B:-"$HOME/.config"}; echo $A; echo $B
    /home/kibi/.config
    
    kibi@tokyo:~$ unset A; unset B; export A=${B:="$HOME/.config"}; echo $A; echo $B
    /home/kibi/.config
    /home/kibi/.config
    

    Mais comme dans ton cas il s'agit d'une seule et même variable…

    Debian Consultant @ DEBAMAX

    • [^] # Re: Éléments de réponse

      Posté par  . Évalué à 5 (+4/-0). Dernière modification le 20 mars 2024 à 22:28.

      C'est pas des plus claire ces histoires de 'substitute' 'asigne' 'parameter' …
      Mais un exemple vaut mille mots:

      parameter=’value’ parameter= unset parameter
      ${parameter:-word} value word word
      ${parameter-word} value null word
      ${parameter:=word} value word word
      ${parameter=word} value null word
      ${parameter:?word} value error, exit error, exit
      ${parameter?word} value null error, exit
      ${parameter:+word} word null null
      ${parameter+word} word word null
  • # 3è point

    Posté par  (site web personnel, Mastodon) . Évalué à 3 (+1/-0). Dernière modification le 20 mars 2024 à 13:15.

    C'est vraisemblablement pas une commande bien que avec mon zsh configuré pour que le mot passe en vert si la commande existe (même principe que avec fish); ":" est en vert.
    Par contre man : ou : -h --help ne fonctionne pas :)

    Il s’agit d’une commande interne, et seule les commandes externes ont une page dédiée (dit comme ça, ça peut surprendre mais POSIX demande que certaines commandes internes soient disponibles en externe aussi, cas de true et test par exemple.) Avec Bash par exemple tu pourrais avoir…

    $ help :
    :: :
        No effect; the command does nothing.  A zero exit code is returned.

    …sinon faut passer par man $(basename $SHELL) puis rechercher dans la page :)
    Édition : C’est aussi listé dans man builtins où on indique aussi ce qui doit exister aussi en commande externe et la compatibilité avec csh.

    Il s’agit d’une commande historique (i.e. les premiers shell Bourne) bien avant l’apparition des commandes true et false, ce qui fait qu’on les retrouve dans certaines constructions de dinosaures…

    if ma_commande; then :; else echo "échec"; fi

    …où on pourrait utiliser les nouvelles commandes plus lisibles.

    if ! ma_commande; then echo "échec"; fi

    C’est encore utile dans certains rares cas comme l’exemple que tu cites, ou les blocs de commentaires (dans le shell on ne sait normalement faire que des commentaires avec le croisillon, mais voici)

    : << 'SKIP'
    
    bloc de code inactif
    
    SKIP

    Du coup, pour en revenir à l’exemple initial, c’est une erreur si on n’indique pas une affectation ou une commande à exécuter (c’est OK si ta variable après évaluation donne une commande…)

    $ echo $SHELL
    /bin/bash
    $ $SHELL -c pwd
    /home/me
    $ $HOME
    -bash: /home/me: is a directory

    Et dans le cas présent, le “no-op” remplace la commande (j’utilise echo à la place en phase de débogage) et on n’a donc pas d’erreur.

    : ${vartest:=DEFAULT}

    se traduirait (façon plus moderne, donc moins dinosaure/exotérique)

    if [ -z "$vartest" ]
    then
        vartest="DEFAULT"
    fi

    …ou encore simplement

    vartest=${vartest:=DEFAULT}

    “It is seldom that liberty of any kind is lost all at once.” ― David Hume

    • [^] # Re: 3è point

      Posté par  . Évalué à 1 (+0/-0). Dernière modification le 20 mars 2024 à 23:07.

      Avec Bash par exemple tu pourrais avoir…

      $ help :
      :: :
      No effect; the command does nothing. A zero exit code is returned.

      Pour le coups, ca me pose un autre problème / interrogation.
      Il me semblait que zsh disposait du même fonctionnement que bash mais avec des fonctionnalités supplémentaire. Ou autrement dit qu'un script bash pouvait fonctionner en zsh (au crontraire des script bash avec fish).

      Donc partant de là help : aurait du fonctionner en zsh, mais ce n'est effectivement pas le cas.

      Tien d'autre différences au passage
      En bash les commande suivantes fonctionne:

      type -t ls
      type --help
      # et donc aussi 
      help :

      Mais pas en zsh !

      NB: Je n'utilise zsh que en shell sur mon pc; mes scripts shell sont toujours en bash

      • [^] # Re: 3è point

        Posté par  (site web personnel, Mastodon) . Évalué à 2 (+0/-0).

        Ce help est une autre commande interne à bash qui lui permet de renseigner sur ses commandes internes…
        Je lis que pour zsh c’est plutôt la fonction run-help à charger et configurer.
        Un coup de man zshbuiltins est possible dans ton cas : il y a une description de : [ arg ... ] ;)

        De même, type est une commande interne reprise de ksh et qui va un peu plus loin (et avec ses incompatibilités) que which (et whereis ?) Tous les interpréteurs ne connaissent pas type et quand c’est le cas ne reconnaissent pas toutes les mêmes options.
        Pour compléter, zsh propose whence

        “It is seldom that liberty of any kind is lost all at once.” ― David Hume

  • # 1e point

    Posté par  (site web personnel, Mastodon) . Évalué à 3 (+1/-0).

    1) Concernant l'aspect langue (linguistique). Je reconnais que mon anglais est ce qu'il est mais:

    Pour le coup, je pense que la problématique demeure …car les traductions françaises gardent aussi les termes “paramètres” et “expansion” heureusement (sans quoi on peut induire des contresens ou des incohérences par rapport au reste de la littérature sur le sujet.)

    • Je ne comprend pas l’emploi du mot "parameter", cela ne devrait pas être "variable" ?

    Le mécanisme a été pensé pour les “paramètres positionnels” et l’usage du mot “variable” aurait laissé croire qu’il s’agissait des variables créées par les usagers uniquement (et qui ne peuvent pas être des chiffres.)

    • même chose pour "expansion", "replace" ou quelque chose comme cela ne serait pas mieux ?

    Par rapport aux paramètres, c’est la phase où le shell “développe” la ligne de commandes. Certaines choses ressemblent à des remplacements mais ce n’est pas toujours le cas : on peut vider certaines variables si l’on veut, on fait des substitutions dans les chaînes, on liste des fichiers (penser au métacaractère astérisque par exemple), etc (penser à la concaténation des blancs multiples en une seule espace par exemple). Cette phase se termine par une recomposition complète (tokenisation ?) de ce qui est saisi, et c’est cette dernière qui va passer à l’exécution.

    “It is seldom that liberty of any kind is lost all at once.” ― David Hume

  • # man bash "Développement des paramètres"

    Posté par  . Évalué à 3 (+2/-0). Dernière modification le 20 mars 2024 à 14:19.

    Bonjour

    … Par contre man : ou : -h --help ne fonctionne pas :) …

    Une ligne de commande pour accéder directement au chapitre concerné :

    man --pager='less -p "Développement des paramètres"' bash
    

    et au cas où tu utiliserais autre chose que le français :

    LANG=C man --pager='less -p "Parameter Expansion"' bash
    

Envoyer un commentaire

Suivre le flux des commentaires

Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.