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?
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)
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.
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).
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.
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