Warum sind Großbuchstaben in einer Reihe von Kleinbuchstaben in einem awk-Regex enthalten?

7
$ echo ABC | awk '$0 ~ /^[a-b]/'
ABC
$ echo ABC | awk '$0 ~ /^[a-a]/'
$ echo ABC | awk '$0 ~ /^a/'
$ 

Sie sehen. /[a-b]/erfasst A, aber /[a-a]/oder /a/nicht. Warum?

Cheng
quelle
1
Siehe Beeinflusst (sollte) LC_COLLATE die Zeichenbereiche? Weitere (ungelöste) Informationen zu diesem Thema.
Caleb
Dies scheint mehr als nur ein einfaches (?) LC_COLLATE-Problem zu sein, da die Verwendung einiger Nicht-C-Werte für LC_COLLATE je nach verwendetem Dienstprogramm zu unterschiedlichen Ergebnissen führt. z.B. 'sed' und 'grep' geben 'awk' unterschiedliche Ergebnisse, wenn LC_COLLATE = en_AU.UTF-8 oder en_US.UTF-8 verwendet wird. sed und grep können das Fallproblem lösen, und es werden nur Kleinbuchstaben gedruckt ( unter Verwendung der gleichen Werte wie oben)
Peter.O
Zumindest in gawk (GNU Awk) wurde dies seit Version 4.0 behoben ([az] stimmt nur mit Kleinbuchstaben überein): gnu.org/software/gawk/manual/html_node/Ranges-and-Locales.html
Piotr Jurkiewicz

Antworten:

6

Ich denke, es ist ein "Gebietsschema" -Problem.

In meinem Gebietsschema it_IT das folgende Snippet

if [[ a < A ]]; then
  echo "a < A"
elif [[ a > A ]]; then
  echo "a > A"
else
  echo "a = A"
fi

if [[ b < A ]]; then
  echo "b < A"
elif [[ b > A ]]; then
  echo "b > A"
else
  echo "b = A"
fi

zeigt an

a < A
b > A

das Aist also (überraschenderweise) zwischen aund b, also im bereich.

Versuchen Sie es auszuführen

echo ABC | LC_COLLATE=C awk '$0 ~ /^[a-b]/'

Bearbeiten

Der folgende Befehl zeigt die Sortierreihenfolge in Ihrem Gebietsschema an:

echo $(LC_COLLATE=C printf '%s\n' {A..z} | sort)

Die Ausgabe auf meinem Computer ist

` ^ _ [ ] a A b B c C d D e E f F g G h H i I j J k K l L m M n N o O p P q Q r R s S t T u U v V w W x X y Y z Z

(kann auf der Handbuchseite von bash nicht verstehen, ob Sequenzausdrücke in der Reihenfolge der Sortierung des Gebietsschemas erweitert sind oder nicht; es scheint nicht).

Enzotib
quelle
+1, aber für diesen speziellen Fall benötigen Sie nur LC_COLLATE, nicht LC_ALL.
Mattdm
@ Mattdm: Sie haben Recht, ich bin faul
Enzotib
@enzotib: Ich bin verwirrt ... Diese Idee scheint zu bedeuten, dass ich jedes Mal, wenn ich einen Bereich / [ax] / festlegen möchte, LC_COLLATE verwenden muss .... Was um alles in der Welt muss eine Sortiersequenz tun, um zu identifizieren, was ist Groß- und Kleinschreibung? ... Ich kann nicht sehen, wie eine Sortiersequenz vorschreibt, was Großbuchstaben sind und was nicht ... Ich setze mich immer wieder mit diesen Gebietsschemaproblemen auseinander und mache langsam Fortschritte, aber diese hat mich verblüfft.
Peter.O
@fred: häufig, wenn ich oder ähnliches benutze sort, joinbeginne ich meine Skripte mit export LC_COLLATE=C. Jetzt muss ich auf diese Weise auch Skripte mit awk:)
enzotib
2
Die Reihenfolge der Sequenzbewertung spielt in diesem Fall keine Rolle , da Sie nach der Generierung der Sequenz sortieren. Ihr Beispiel würde jedoch mit LC_COLLATE neben sortieren genauer funktionieren: "echo $ (printf '% s \ n' {A..z} | LC_COLLATE = 'C' sortieren)" ... was sich korrekt vom Standard abheben würde case "echo $ (printf '% s \ n' {A..z} | LC_COLLATE = '' sort)". Die obige ursprüngliche Syntax wendet das lokal geänderte LC_COLLATE niemals auf den Sortierbefehl an [natürlich sind alle Wetten deaktiviert, wenn LC_ALL irgendwo gesetzt wurde ...]
MartyMacGyver