web-dev-qa-db-ger.com

Welche Regeln gelten für gültige Bezeichner (z. B. Funktionen, Variablen usw.) in Bash?

Wie lauten die Syntaxregeln für Bezeichner, insbesondere die Funktions- und Variablennamen in Bash?

Ich habe ein Bash-Skript geschrieben und auf verschiedenen Versionen von Bash unter Ubuntu, Debian, Red Hat 5 und 6 sowie einer alten Solaris 8-Box getestet. Das Skript lief gut und wurde ausgeliefert.

Wenn ein Benutzer es jedoch auf SUSE-Computern ausprobierte, gab es den Fehler "keine gültige Kennung". Zum Glück war meine Vermutung, dass der Funktionsname ein ungültiges Zeichen enthielt, richtig. Die Bindestriche haben es durcheinander gebracht.

Die Tatsache, dass ein Skript, das zumindest ein wenig getestet wurde, ein völlig anderes Verhalten auf einer anderen Bash oder Distribution hatte, war beunruhigend. Wie kann ich das vermeiden?

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

name ist an anderer Stelle definiert:

       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.

Bindestriche sind also nicht gültig. Und doch funktionieren sie auf meinem System ...

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

Die Frage betraf "die Regeln", die auf zwei verschiedene Arten beantwortet wurden, von denen jede in gewissem Sinne korrekt ist, je nachdem, was Sie "Regeln" nennen wollen. Um @ ricis Punkt näher zu erläutern, dass Sie einen beliebigen Namen in einem Funktionsnamen verwenden können, habe ich ein kleines Bash-Skript geschrieben, um zu versuchen, check jedes mögliche Zeichen (0-255) als Funktionsnamen sowie als das zweite Zeichen eines Funktionsnamens:

#!/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

Ich überspringe eigentlich NUL (0x00), da dies das ein Zeichen ist, das die Bash im Eingabestrom finden kann. Die Ausgabe dieses Skripts lautete:

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!

Beachten Sie, dass ich bash gerne meine Funktion "[} {" nennen kann. Mein Code ist wahrscheinlich nicht streng genug, um die genauen Regeln für die Legalität in der Praxis anzugeben, aber er sollte einen Eindruck davon geben, welche Art von Missbrauch möglich ist. Ich wünschte, ich könnte diese Antwort als "Nur für reife Zielgruppen" markieren.

6
Ron Burk

Befehlsbezeichner und Variablennamen haben unterschiedliche Syntax. Ein Variablenname ist auf alphanumerische Zeichen und Unterstriche beschränkt und beginnt nicht mit einer Ziffer. Ein Befehlsname dagegen kann fast alles sein, das keine Bash-Metazeichen enthält (und selbst dann können sie in Anführungszeichen gesetzt werden).

In bash können Funktionsnamen Befehlsnamen sein, sofern sie als Word ohne Anführungszeichen analysiert werden. (Abgesehen davon, dass sie aus irgendeinem Grund keine ganzen Zahlen sein können.) Dies ist jedoch eine Bash-Erweiterung. Wenn der Zielcomputer eine andere Shell (z. B. Bindestrich) verwendet, funktioniert er möglicherweise nicht, da die Posix-Standard-Shell-Grammatik nur "NAME" im Funktionsdefinitionsformular zulässt (und auch die Verwendung von reservierten Wörtern verbietet).

6
rici

Von 3.3 Shell-Funktionen :

Shell-Funktionen bieten eine Möglichkeit, Befehle zur späteren Ausführung mit einem einzigen Namen für die Gruppe zu gruppieren. Sie werden wie ein "regulärer" Befehl ausgeführt. Wenn der Name einer Shell-Funktion als einfacher Befehlsname verwendet wird, wird die Liste der Befehle ausgeführt, die diesem Funktionsnamen zugeordnet sind. Shell-Funktionen werden im aktuellen Shell-Kontext ausgeführt. Es wird kein neuer Prozess erstellt, um sie zu interpretieren.

Funktionen werden mit dieser Syntax deklariert:

name () compound-command [ redirections ]

oder

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

und ab 2 Definitionen :

name

Ein Wort, das nur aus Buchstaben, Zahlen und Unterstrichen besteht und mit einem Buchstaben oder Unterstrich beginnt. Namen werden als Shell-Variablen- und Funktionsnamen verwendet. Wird auch als Bezeichner bezeichnet.

2
Etan Reisner

Dieses Skript testet alle gültigen Zeichen mit einem Zeichen auf Funktionsnamen.


Es gibt 53 gültige Zeichen (a-zA-Z und Unterstrich) mit aus
a POSIX Shell und 220 gültige Zeichen mitBASHv4.4.12.

Die Antwort von Ron Burk ist gültig, es fehlen jedoch die Zahlen.

#!/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