• Willkommen im Linux Club - dem deutschsprachigen Supportforum für GNU/Linux. Registriere dich kostenlos, um alle Inhalte zu sehen und Fragen zu stellen.

case-Konstrukt bereitet Schwierigkeiten...

gh0st124

Newbie
Hi,

habe folgendes Skript geschrieben zur Erkennung von Zeichen.
Das Skript funktioniert aber nicht richtig. Z.B. wenn ich das Skript mit einem Großbuchstaben starte, dann bekomme ich als Resultat Kleinbuchstabe. Woran kann das liegen?

Sollte ich dieses Konstrukt lieber meiden und switch benutzen? Wenn ja, wie sieht das äquivalente switch-Konstrukt aus?

Ich benutze die bash (Suse 9.2).

Code:
#! /bin/sh
if [ $# -ne 1 ]
then
    echo "$0: falsche Anzahl von Argumenten" >&2
    echo "usage: $0 character"               >&2
    exit 1
fi

case "$1" in
    [0-9]) echo "Ziffer";;
    [a-z]) echo "Kleinbuchstabe";;
    [A-Z]) echo "Großbuchstabe";;
    ?)     echo "unbekanntes Zeichen";;
    *)     echo "Fehler: Nur ein Zeichen erlaubt" >&2;;
esac

Vielen Dank
 
A

Anonymous

Gast
mach mal in deinem Script einen Rundumschlag der Lang-Variablen dann sollte es gehen
Code:
#! /bin/bash

export LANG=C
export LC_ALL=C

robi
 
OP
G

gh0st124

Newbie
Klappen tut es schon aber ich habe jetzt noch mehr Probleme wie vorher:

1. ...würde ich gerne verstehen, weshalb ich die Sprache auf C???? umstellen soll.
2. ...jetzt habe ich Probleme mit den Umlauten (werden nicht richtig angezeigt).
 
A

Anonymous

Gast
zu 1. wenn du das Kommando locale -a abgibst, bekommst du die Ausgabe aller möglichen Belegungen für die LANG-Variablen.
dort gibt es auch dieses C und POSIX das ist die originalen Einstellungen ohne irgendwelches landesspezifisches Geschnörksel und sonstiges und natürlich ohne Deutsche Umlaute.

zu 2. In der bash und in den bashbuiltins gibt es an einigen Stellen Probleme mit der Verarbeitung einiger Großbuchstaben, einige gehen zB Y andere nicht zb A. woran das liegt habe ich auch noch nicht herausgefunden, aber alle möglichen Versuche das mit Bashoptionen wegzubekommen haben bei mir bis jetzt versagt, mit Ausnahme die LANG-Variablen auf C oder POSIX zu stellen.

Also wenn so was in einem Script bei mir anliegt, setze ich diese Variablen im Script um, und muss dabei aber auch bedenken, dass mir dann nicht mehr der gesamte deutsche Zeichenbereich in diesem Script zur Verfügung steht.

Vieleicht haben ja die Spezis hier im Forum eine bessere Erklärung oder gar eine richtige Lösung

robi
 

regexer

Advanced Hacker
gh0st124 schrieb:
Ich benutze die bash (Suse 9.2).

Code:
#! /bin/sh
...
Sorry, aber mit diesem Script benutzt du die bash nicht. Siehe erste Zeile. Außerdem kommt zwischen dem Rufezeichen und dem ersten Slash kein leerzeichen.

Übrigens funktioniert das Script bei mir (SLES 8 ) sowohl mit der bash als auch mit der sh ohne Probleme...
 

TeXpert

Guru
notoxp schrieb:
gh0st124 schrieb:
Ich benutze die bash (Suse 9.2).

Code:
#! /bin/sh
...
Sorry, aber mit diesem Script benutzt du die bash nicht.
doch :) sh ist auf vielen Linux-Distris nur ein Link auf die 'Default'-Shell

Code:
> ls -l /bin/sh
lrwxrwxrwx  1 root root 4 2005-01-15 14:53 /bin/sh -> bash
Siehe erste Zeile. Außerdem kommt zwischen dem Rufezeichen und dem ersten Slash kein leerzeichen.
auch das spielt keine Rolle, die Syntax ist 'shebang [Interpreter]' und da können beliebig viele Whitespaces zwischen sein, es muss nur in einer Zeile stehen
[/code]
 

snaewe

Hacker
TeXpert schrieb:
doch :) sh ist auf vielen Linux-Distris nur ein Link auf die 'Default'-Shell

Code:
> ls -l /bin/sh
lrwxrwxrwx  1 root root 4 2005-01-15 14:53 /bin/sh -> bash
Allerdings verhält sich die Bash ein wenig anders, wenn sie als 'sh' gestartet wird.

Stefan
 

taki

Advanced Hacker
Hallo.
Im SuSE-Portal findet sich ein Eintrag, der ganz gut erklärt, was es mit dem LC_ALL=C auf sich hat. Nach dem Poxix2 Standard verhält sich u.a. die Sortierreihenfolge je nach Locale unterschiedlich.

Dummerweise gilt in unserer Locale, dass nicht zwischen Groß- und Kleinbuchstaben unterschieden wird. Mit LC_ALL=C setzt man alle Locale-Variablen gleichzeitig auf C, damit man im Script eine definierte Umgebung hat, auf die man sich dann bei Sortierungen u.ä. verlassen kann.
Gruß,
Taki


http://portal.suse.com/sdb/de/2004/06/bash_posix2.html
 
A

Anonymous

Gast
danke taki --- hatte das noch nicht gefunden.

die Erklärung das das nur auf die Suchreihenfolge zurückzuführen ist, hat somit aber weitreichende Auswirkungen auf die Angabe von Bereichen.
der Bereich [a-z] bedeutet für die bash somit
aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYz
und der Bereich [A-Z] bedeutet somit
AbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ

die einzige Möglichkeit vernünftig damit umzugehen ist außerhalb von LC_ALL=C also nur ganz auf die Angabe von Bereichen zu verzichten.
Code:
case "$1" in
    [0-9]) echo "Ziffer";;
    [abcdefghijklmnopqrstuvwxyz]) echo "Kleinbuchstabe";;
    [ABCDEFGHIJKLMNOPQRSTUVWXYZ]) echo "Großbuchstabe";;
    ?)     echo "unbekanntes Zeichen";;
    *)     echo "Fehler: Nur ein Zeichen erlaubt" >&2;;
esac

Im Gegenteil man müsste Bereiche zB [a-z] und [A-Z] außerhalb einer genau definierten LC_ALL Variable komplett verbieten, da der Scriptablauf dann von dem Wert von LC_ALL abhängt und nicht von dem was der Schreiber des scripte programmieren wollte.
Man denke nur an folgende Zeile in einem Script
Code:
rm [A-Z]*.*

Ob das wohl im Sinne des Erfinders liegt :?: :?: :?:
Oder ob ist das ehr in die Kiste mit den Bugs einzuordnen ist :wink:

robi

PS: habe jetzt mal einige Tests gemacht, wer also denkt mit LC_ALL=de_DE@euro und [a-C] könne er nur ABCabc ausfiltern wird staunen
da passen A B C a b c ª À Á Â Ã Ä Å Æ à á â ã ä å æ
und [a-Z] bringt immerhin A B C D E F G H I J K L M N O P Q R S T U V W X Y Z a b c d e f g h i j k l m n o p q r s t u v w x y z Š š ª º Œ œ Ÿ À Á Â Ã Ä Å Æ Ç È É Ê Ë Ì Í Î Ï Ð Ñ Ò Ó Ô Õ Ö Ø Ù Ú Û Ü Ý ß à á â ã ä å æ ç è é ê ë ì í î ï ð ñ ò ó ô õ ö ø ù ú û ü ý ÿ
was das jetzt noch mit Deutsch zu tun hat, muss mir erst mal jemand erklären

Das selbe jetzt mit LC_ALL=C probiert ergibt weder bei [a-C] noch bei [a-Z] überhaupt einen Treffer, hier muss das Argument geändert werden auf [A-c] und [A-z] mit folgendem Ergebniss
A B C D E F G H I J K L M N O P Q R S T U V W X Y Z [ \ ] ^ _ ` a b c
A B C D E F G H I J K L M N O P Q R S T U V W X Y Z [ \ ] ^ _ ` a b c d e f g h i j k l m n o p q r s t u v w x y z

in beiden Fällen fallen hier einige Sonderzeichen [ \ ] ^ _ ` mit in den Suchbereich.

So jetzt sollten wohl alle Unklarheiten ein für allemal beseitigt sein.
Ach so, für alle die noch weitertesten wollen oder müssen hier der verwendete Zeichengenerator
Code:
 for i in {0,1,2,3}{0,1,2,3,4,5,6,7}{0,1,2,3,4,5,6,7}
 do ZEICHEN=`echo -e "\0$i"`
 ./script   $ZEICHEN
 done

robi
 

regexer

Advanced Hacker
TeXpert schrieb:
auch das spielt keine Rolle, die Syntax ist 'shebang [Interpreter]' und da können beliebig viele Whitespaces zwischen sein, es muss nur in einer Zeile stehen
Hast recht! Zwischen Hash und Rufezeichen darf kein Whitespace sein. Da habe ich zu schnell geschossen! :oops:
 

regexer

Advanced Hacker
robi schrieb:
So jetzt sollten wohl alle Unklarheiten ein für allemal beseitigt sein.
Nö! Ich verstehe nach wie vor mein System nicht.
Code:
~> test.sh A
Großbuchstabe
~> test.sh Ä
unbekanntes Zeichen
~> test.sh a
Kleinbuchstabe
~> test.sh ä
unbekanntes Zeichen
~> echo "a\nb\nä\nA\nB" | sort
A
B
a
b
ä
~> touch a A ä b
~> ls [A-Z]
A
~> ls [a-z]
a  b
~> ls [A-z]
A  a  b
~> ls [a-zä]
a  b  ä
~> ls [a-Z]
ls: [a-Z]: Datei oder Verzeichnis nicht gefunden
~> locale
LANG=de_DE@euro
LC_CTYPE="de_DE@euro"
LC_NUMERIC="de_DE@euro"
LC_TIME="de_DE@euro"
LC_COLLATE=POSIX
LC_MONETARY="de_DE@euro"
LC_MESSAGES="de_DE@euro"
LC_PAPER="de_DE@euro"
LC_NAME="de_DE@euro"
LC_ADDRESS="de_DE@euro"
LC_TELEPHONE="de_DE@euro"
LC_MEASUREMENT="de_DE@euro"
LC_IDENTIFICATION="de_DE@euro"
LC_ALL=
~>

Nachtrag: Mir ist selber die Erleuchtung gekommen! LC_COLLATE steht bei mir auf POSIX. Und das ist für das case zuständig! Wer also die deutschen Meldungstexte behalten will, jedoch internationales case haben will, tut gut daran, nur LC_COLLATE auf "C" zu setzen! Man braucht also nicht mit LC_ALL zu arbeiten.
 

regexer

Advanced Hacker
gh0st124 schrieb:
Klappen tut es schon aber ich habe jetzt noch mehr Probleme wie vorher:

1. ...würde ich gerne verstehen, weshalb ich die Sprache auf C???? umstellen soll.
2. ...jetzt habe ich Probleme mit den Umlauten (werden nicht richtig angezeigt).

Ich möchte also nochmal auf der Ausgangsproblem von gh0st124 zurückkommen. LC_ALL=C verstellt zu viele Optionen. Gegen das Problem hilft ein ganz einfaches:
Code:
export LC_ALL=""
export LC_COLLATE=POSIX

collate beeinflusst nämlich nur die Sortierreihenfolge. Jetzt hast du dann nur die Umlaute nach dem "z" einsortiert...
 
OP
G

gh0st124

Newbie
erst einmal vielen Dank dafür, dass Ihr euch Zeit genommen habt (ich weiß die Zeit zu schätzen).

Mich interessiert eigentlich weniger die technische Realisierung. Mich interessiert das "Wieso" (ich fühl mich jetzt wie Morpheus).

Also so viel habe ich mitgenommen:

Die Sprachbelegung bereitet Schwierigkeiten. Standardmäßig ist bei mir (bei euch dann wohl auch) de_DE.UTF-8 in der LANG Variable gespeichert. Das muss ich dann irgendwie (sei es durch LANG=C oder LC_ALL=C) ändern.

Frage1: Wieso gibt es eigentlich mehrere aktive Belegungen, oder besser: wieso muss ich alle Belegungen auf C setzen oder laut notoxp gar nicht setzen, also LC_ALL=""?

Frage2: Hab ich Recht mit der Annahme, dass ich LC_COLLATE auf Posix oder C setzen muss, WEIL sonst die Ordnung/Reihenfolge bei z.B. [a..z] nicht der Ordnung entsprechen würde, die ich annehmen würde?

Frage3: soll ich in Zukunft im HeaderTeil des Skripts immer diesen Code von notoxp schreiben oder wie macht ihr das?

Vielen Dank
 
A

Anonymous

Gast
gh0st124 schrieb:
Die Sprachbelegung bereitet Schwierigkeiten. Standardmäßig ist bei mir (bei euch dann wohl auch) de_DE.UTF-8 in der LANG Variable gespeichert. Das muss ich dann irgendwie (sei es durch LANG=C oder LC_ALL=C) ändern.

Frage1: Wieso gibt es eigentlich mehrere aktive Belegungen, oder besser: wieso muss ich alle Belegungen auf C setzen oder laut notoxp gar nicht setzen, also LC_ALL=""?

Frage2: Hab ich Recht mit der Annahme, dass ich LC_COLLATE auf Posix oder C setzen muss, WEIL sonst die Ordnung/Reihenfolge bei z.B. [a..z] nicht der Ordnung entsprechen würde, die ich annehmen würde?

Frage3: soll ich in Zukunft im HeaderTeil des Skripts immer diesen Code von notoxp schreiben oder wie macht ihr das?

Also du brauchst keine Angst zu haben, dass die Buchstaben mal sortiert so hier aussehen "A X C Ü N" und du brauchst prinzipiell nicht in jedem Script an den LC_.... Variablen rumzustellen.

Aber dir sollte bewusst sein, wenn du Deutsch eingestellt hast dann ist die Sortierfolge " a A ä Ä b B c C ........." wenn du Posix eingestellt hast dann "A B C........ a b c ..... Ä...ä " und in anderen Spachen kann das noch ganz anders aussehen.

Wenn du im Script [ABCDEFG] verwendest, ist das immer richtig und wenn du [A-G] verwenden möchtest, dann musst du vorher genau die LC_.... definieren, da sonst eventuell beim Start des scriptes aus einem anderem Terminal oder als anderer User etwas falsches passiert weil du plötzlich eine andere Sortierreihenfolge hast, und damit der Bereich auch Buchstaben umfasst, die er nicht umfassen sollte.

Man sollte beim Testen von Scripten auch daran denken, dass das Script auch mal aus einer bash mit anderer LC_ALL Einstellungen gestartet werden könnte

robi
 

regexer

Advanced Hacker
gh0st124 schrieb:
Frage1: Wieso gibt es eigentlich mehrere aktive Belegungen, oder besser: wieso muss ich alle Belegungen auf C setzen oder laut notoxp gar nicht setzen, also LC_ALL=""?
Alle Belegungen auf C zu setzten (Mit LC_ALL=C) würde heißen, auch die Error-Texte in Englisch auszugeben. Wenn ich Dich richtig verstanden habe, wollen wir bei deinem Problem eigentlich nur die Sortierreihenfolge ändern. Und das passiert mit LC_COLLATE=... Beim Testen habe ich gemerkt, dass man LC_COLLATE nicht setzen kann, solange LC_ALL gesetzt ist. Deswegen muss man LC_ALL erstmal auf nichts setzen.

gh0st124 schrieb:
Frage2: Hab ich Recht mit der Annahme, dass ich LC_COLLATE auf Posix oder C setzen muss, WEIL sonst die Ordnung/Reihenfolge bei z.B. [a..z] nicht der Ordnung entsprechen würde, die ich annehmen würde?
Korrekt!

gh0st124 schrieb:
Frage3: soll ich in Zukunft im HeaderTeil des Skripts immer diesen Code von notoxp schreiben oder wie macht ihr das?
Das wäre natürlich eine Möglichkeit. Aber ich finde sie nicht sauber. Ich würde ein solches case-Konstukt entweder vermeiden oder ausschreiben (also: [ABCDEF...]). Denn wie schon robi gesagt hat, kann man ja nicht garantieren, mit welchen Einstellungen das Script gestartet wurde.

Ansonsten kannst du natürlich auch die Einstellungen von LC_... während des Bootvorgangs festlegen. Ich müsste jetzt nur nachsehen, welche Datei man hierzu editieren muss. Wahrscheinlich geht's auch irgendwie einfacher mit YaST.
 

regexer

Advanced Hacker
robi schrieb:
Aber dir sollte bewusst sein, wenn du Deutsch eingestellt hast dann ist die Sortierfolge " a A ä Ä b B c C ........." wenn du Posix eingestellt hast dann "A B C........ a b c ..... Ä...ä " und in anderen Spachen kann das noch ganz anders aussehen.
Anscheinend ist das wirklich nur die Sortierreihenfolge. Bei meinen Tests hatte das nur Auswirkungen auf case, sort und ls. Deine Bedenken bezüglich rm haben sich zum Glück nicht bewahrheitet.
robi schrieb:
Man denke nur an folgende Zeile in einem Script
Code:
rm [A-Z]*.*
Das wird offensichtlich "ganz normal" von der Shell evaluiert...
 
A

Anonymous

Gast
notoxp schrieb:
Man denke nur an folgende Zeile in einem Script
Code:
rm [A-Z]*.*
Das wird offensichtlich "ganz normal" von der Shell evaluiert...

Wir hatten hier aber schon mal genau dieses Problem in einem Thread behandelt, leider finde ich es nicht mehr, hat wohl im LINUX-Talk gestanden. Wenn ich mich recht erinnere, wurden Dateien angelegt wie zB : " ll aa AA LL zz ZZ" und dann wurden diese mit "rm [a-z]*" alle gelöscht, bis auf ZZ , außer mit root da ging das nicht, jetzt weiß ich auch warum. Der Titel könnte etwa gehießen haben: "Vorsicht Bug in bash löscht Dateien"

Ich währe mir also nicht so sicher, ob das nicht doch wirklich so ist, habe jetzt gerade kein Suse 9.1 aufwärts hier, ums zu testen

robi
 
A

Anonymous

Gast
ist natürlich genau so wie ich es in Erinnerung hatte.
Code:
robi@dhcppc1:~/test> cd test
robi@dhcppc1:~/test/test> touch aa bb cc dd zz AA BB CC DD ZZ
robi@dhcppc1:~/test/test> ls -l
insgesamt 0
-rw-r--r--  1 rob ftp 0 2005-04-06 23:43 aa
-rw-r--r--  1 rob ftp 0 2005-04-06 23:43 AA
-rw-r--r--  1 rob ftp 0 2005-04-06 23:43 bb
-rw-r--r--  1 rob ftp 0 2005-04-06 23:43 BB
-rw-r--r--  1 rob ftp 0 2005-04-06 23:43 cc
-rw-r--r--  1 rob ftp 0 2005-04-06 23:43 CC
-rw-r--r--  1 rob ftp 0 2005-04-06 23:43 dd
-rw-r--r--  1 rob ftp 0 2005-04-06 23:43 DD
-rw-r--r--  1 rob ftp 0 2005-04-06 23:43 zz
-rw-r--r--  1 rob ftp 0 2005-04-06 23:43 ZZ
robi@dhcppc1:~/test/test> rm [a-z]*
robi@dhcppc1:~/test/test> ls -l
insgesamt 0
-rw-r--r--  1 rob ftp 0 2005-04-06 23:43 ZZ
robi@dhcppc1:~/test/test>
Also allerhöchste ACHTUNG mit solchen Bereichen wie [a-z] oder [A-Z] in der bash !!!
Ist ja auch völlig klar, denn die bash erzeugt ja die Liste der Dateinamen und gibt sie an rm zum löschen, also gilt das für jeden Kommandoaufruf über die bash.

robi
 

regexer

Advanced Hacker
robi schrieb:
Also allerhöchste ACHTUNG mit solchen Bereichen wie [a-z] oder [A-Z] in der bash !!!
Nö! Kann ich wieder nicht nachvollziehen. Das scheint weder am LC_COLLATE noch am LC_ALL zu liegen.
Code:
~> test.sh Ä
unbekanntes Zeichen
~> export LC_ALL=de_DE@euro
~> locale
LANG=de_DE@euro
LC_CTYPE="de_DE@euro"
LC_NUMERIC="de_DE@euro"
LC_TIME="de_DE@euro"
LC_COLLATE="de_DE@euro"
LC_MONETARY="de_DE@euro"
LC_MESSAGES="de_DE@euro"
LC_PAPER="de_DE@euro"
LC_NAME="de_DE@euro"
LC_ADDRESS="de_DE@euro"
LC_TELEPHONE="de_DE@euro"
LC_MEASUREMENT="de_DE@euro"
LC_IDENTIFICATION="de_DE@euro"
LC_ALL=de_DE@euro
~> test.sh Ä
Kleinbuchstabe
~> test.sh B
Kleinbuchstabe
~> touch aa bb cc dd zz AA BB CC DD ZZ
~> rm [a-z]*
~> ls -l
insgesamt 0
-rw-rw-r--    1 user     group           0 Apr  7 07:57 AA
-rw-rw-r--    1 user     group           0 Apr  7 07:57 BB
-rw-rw-r--    1 user     group           0 Apr  7 07:57 CC
-rw-rw-r--    1 user     group           0 Apr  7 07:57 DD
-rw-rw-r--    1 user     group           0 Apr  7 07:57 ZZ
~>
Die Suche geht weiter ...
 
A

Anonymous

Gast
ich hab noch Suse 9.1 und GNU bash, version 2.05b.0(1)-release (i586-suse-linux) drauf, mein System ist auch nicht 100% gepatcht ,
also denke ich mal, das man doch irgendwann mal das etwas entschärft hat.

Na vielleicht hatten ja einige nicht fließend Englisch sprechende Entwickler mal Scripte mit
Code:
rm -rf /[A-Z]*
geschrieben und sich gewundert, dass nach update und dem Ausführen des scriptes unter root immer LINUX neu zu installieren war :lol:
Wenns unter 9.2 nicht mehr so extrem streng ist, dann finde ich kann man damit leben, muss man eben ab und zu das Hirnschmalz mal etwas bemühen wenn man scripte schreibt.

robi
 
Oben