web-dev-qa-db-fra.com

Quelles sont les règles pour les identificateurs valides (par exemple, fonctions, vars, etc.) dans Bash?

Quelles sont les règles de syntaxe pour les identificateurs, en particulier les noms de fonction et de variable, dans Bash?

J'ai écrit un script Bash et l'ai testé sur différentes versions de Bash sous Ubuntu, Debian, Red Hat 5 et 6, et même sur une vieille boîte Solaris 8. Le script a bien fonctionné, il a donc été expédié.

Pourtant, lorsqu'un utilisateur l'essayait sur des machines SUSE, une erreur "Identificateur non valide" était générée. Heureusement, mon hypothèse était qu'il y avait un caractère invalide dans le nom de la fonction. Les traits d'union fouillaient tout.

Le fait qu'un script au moins quelque peu testé aurait un comportement complètement différent sur un autre Bash ou une autre distribution était déconcertant. Comment puis-je éviter ça?

20
labyrinth
   Shell Function Definitions
       ...
       name () compound-command [redirection]
       function name [()] compound-command [redirection]

name est défini ailleurs:

       name   A  Word  consisting  only  of alphanumeric characters and under‐
              scores, and beginning with an alphabetic character or an  under‐
              score.  Also referred to as an identifier.

Donc, les traits d'union ne sont pas valides. Et pourtant, sur mon système, ils fonctionnent ...

$ bash --version
GNU bash, version 4.2.25(1)-release (x86_64-pc-linux-gnu)
21
Thomas

La question portait sur "les règles", auxquelles il a été répondu de deux manières différentes, chacune correcte dans un certain sens, en fonction de ce que vous voulez appeler "les règles". Juste pour préciser le point de @ rici selon lequel vous pouvez déplacer n'importe quel caractère dans un nom de fonction, j'ai écrit un petit script bash pour essayer de vérifier tous les caractères possibles (0-255) en tant que nom de fonction, ainsi que le deuxième caractère d'un nom de fonction:

#!/bin/bash
ASCII=( nul soh stx etx eot enq ack bel bs tab nl vt np cr so si dle \
            dc1 dc2 dc3 dc4 nak syn etb can em sub esc fs gs rs us sp )

for((i=33; i < 127; ++i)); do
    printf -v Hex "%x" $i

    printf -v Chr "\x$Hex"
    ASCII[$i]="$Chr"
done
ASCII[127]=del
for((i=128; i < 256; ++i)); do
    ASCII[$i]=$(printf "0X%x" $i)
done

# ASCII table is now defined

function Test(){
    Illegal=""
    for((i=1; i <= 255; ++i)); do
        Name="$(printf \\$(printf '%03o' $i))"
        eval "function $1$Name(){ return 0; }; $1$Name ;" 2>/dev/null
        if [[ $? -ne 0 ]]; then
            Illegal+=" ${ASCII[$i]}"
            #        echo Illegal: "${ASCII[$i]}"
        fi
    done
    printf "Illegal: %s\n" "$Illegal"
}
echo "$BASH_VERSION"
Test
Test "x"

# can we really do funky crap like this?
function [}{(){
   echo "Let me take you to, funkytown!"
}
[}{    # why yes, we can!
# though editor auto-indent modes may punish us

En fait, je saute NUL (0x00), car c’est le caractère que bash pourrait s’opposer à la recherche dans le flux d’entrée. La sortie de ce script était:

4.4.0(1)-release
Illegal:  soh tab nl sp ! " # $ % & ' ( ) * 0 1 2 3 4 5 6 7 8 9 ; < > \ ` { | } ~ del
Illegal:  soh " $ & ' ( ) ; < > [ \ ` | del
Let me take you to, funkytown!

Notez que bash me permet de nommer ma fonction "[} {". Mon code n'est probablement pas assez rigoureux pour fournir les règles exactes de la légalité dans la pratique, mais il devrait donner une idée du type d'abus possible. J'aimerais pouvoir marquer cette réponse "Pour un public adulte uniquement".

6
Ron Burk

Les identificateurs de commande et les noms de variables ont des syntaxes différentes. Un nom de variable est limité aux caractères alphanumériques et au trait de soulignement, ne commençant pas par un chiffre. Un nom de commande, en revanche, peut être à peu près tout ce qui ne contient pas de métacaractères bash (et même dans ce cas, ils peuvent être cités).

Dans bash, les noms de fonction peuvent être des noms de commande, à condition qu'ils soient analysés comme un mot sans guillemets. (Sauf que, pour une raison quelconque, ils ne peuvent pas être des entiers.) Cependant, c'est une extension bash. Si la machine cible utilise un autre shell (tel que dash), il est possible que cela ne fonctionne pas, car la grammaire Posix standard du shell autorise uniquement "NOM" dans le formulaire de définition de fonction (et interdit également l'utilisation de mots réservés).

6
rici

A partir de 3.3 Fonctions Shell :

Les fonctions shell permettent de regrouper des commandes pour une exécution ultérieure en utilisant un nom unique pour le groupe. Ils sont exécutés comme une commande "normale". Lorsque le nom d'une fonction Shell est utilisé comme nom de commande simple, la liste des commandes associées à ce nom de fonction est exécutée. Les fonctions du shell sont exécutées dans le contexte actuel du shell. aucun nouveau processus n'est créé pour les interpréter.

Les fonctions sont déclarées en utilisant cette syntaxe:

name () compound-command [ redirections ]

ou

function name [()] compound-command [ redirections ]

et de 2 Définitions :

prénom

Un mot composé uniquement de lettres, de chiffres et de caractères de soulignement et commençant par une lettre ou un soulignement. Les noms sont utilisés en tant que variables shell et noms de fonctions. Aussi appelé identifiant.

2
Etan Reisner

Ce script teste tous les caractères valides pour les noms de fonction avec 1 caractère.


Il génère 53 caractères valides (a-zA-Z et trait de soulignement) en utilisant
a POSIX Shell et 220 caractères valides avecBASHv4.4.12.

La réponse de Ron Burk est valide, mais il manque les chiffres.

#!/bin/sh

FILE='/tmp/FOO'
I=0
VALID=0

while [ $I -lt 256 ]; do {
        NAME="$( printf \\$( printf '%03o' $I ))"
        I=$(( I + 1 ))

        >"$FILE"
        ( eval "$NAME(){ rm $FILE;}; $NAME" 2>/dev/null )

        if [ -f "$FILE" ]; then
                rm "$FILE"
        else
                VALID=$(( VALID + 1 ))
                echo "$VALID/256 - OK: $NAME"   
        fi
} done
0
Bastian Bittorf