Warum stimmen die [az] Sternchen mit den Zahlen überein?


13

Ich habe 3 Verzeichnisse im aktuellen Pfad.

$ls
a_0db_data  a_clean_0db_data  a_clean_data
$ls a_*_data
a_0db_data:

a_clean_0db_data:

a_clean_data:

$ls a_[a-z]*_data
a_clean_0db_data:

a_clean_data:

Ich habe erwartet, dass der letzte ls-Befehl nur übereinstimmt a_clean_data. Warum passte es auch zum Inhalt 0?

bash --version
GNU bash, version 4.2.24(1)-release (i686-pc-linux-gnu)

2
In dieser Frage erfahren Sie mehr über den Unterschied zwischen einem regulären Ausdruck und einem Glob.
terdon

4
Die Tatsache, dass a_*_dataeine dieser Dateien übereinstimmt, hat Sie also nicht überrascht?
Cthulhu

@ Cthulhu du hast mich!
user13107

Antworten:


29

Das [a-z]Teil stimmt nicht mit der Zahl überein. es ist das *. Möglicherweise sind Shell- Globbing und reguläre Ausdrücke verwirrend .

Tools wie grepverschiedene Aromen von regulären Ausdrücken (nehmen Grundstandardmäßig für längere, für Perl regex )-E-P

ZB ( -vinvertiert die Übereinstimmung)

$ ls a_[a-z]*_data | grep -v "[0-9]"
a_clean_data

Wenn Sie einen Bash-Regex verwenden möchten, finden Sie hier ein Beispiel zum Testen, ob die Variable $refeine Ganzzahl ist:

re='^[0-9]+$'
if ! [[ $ref =~ $re ]] ; then
  echo "error"
fi

Wie verwende ich dann Bash Regex? (Siehe tldp.org/LDP/Bash-Beginners-Guide/html/sect_04_01.html )
user13107

1
siehe diese
frage

21

Das Problem ist also: Warum passt a_[a-z]*_datadas a_clean_0db_data?

Dies kann in vier Teile unterteilt werden:

  • a_Entspricht dem Beginn von a_clean_0db_dataund clean_0db_datamuss abgeglichen werden

  • [a-z]Stimmt mit jedem Zeichen im Bereich überein a-z(z. B. c) und lean_0db_datamuss abgeglichen werden

  • * Stimmt mit einer beliebigen Anzahl von Zeichen überein, z lean_0db

  • _data passt zum Trailing _data

In regulären Ausdrücken [a-z]*würde eine beliebige Anzahl von Zeichen (einschließlich Null) im Bereich von a..z bedeuten , aber Sie haben es mit Shell- Globbing zu tun, nicht mit regulären Ausdrücken.

Wenn Sie reguläre Ausdrücke wünschen, haben einige findImplementierungen ein -regexPrädikat dafür:

find . -maxdepth 1 -regex "^.*/a_[a-z]*_data$"

Das -maxdepthist nur hier, um die Suchergebnisse auf den Ordner zu beschränken, in dem Sie sich befinden. Der reguläre Ausdruck entspricht dem gesamten Dateinamen, daher habe ich ein hinzugefügt ^.*/, um den Pfad-Teil abzugleichen


11

*In Shell-Mustern werden 0 oder mehr Zeichen gefunden. Es ist nicht zu verwechseln mit dem *Operator für reguläre Ausdrücke, der 0 oder mehr des vorhergehenden Atoms bedeutet .

*In grundlegenden Shell-Mustern gibt es kein Äquivalent zu regulären Ausdrücken . Verschiedene Shells haben dafür jedoch Erweiterungen.

  • kshhat *(something):

    ls a_*([a-z])_data
  • Sie können das gleiche bashmit shopt -s extgloboder zshmit haben setopt kshglob:

    shopt -s extglob
    ls a_*([a-z])_data
  • In zshmit extendedglobaktiviert #ist gleichbedeutend mit regexp *:

    setopt extendedglob
    ls a_[a-z]#_data
  • In neueren Versionen von ksh93können Sie auch reguläre Ausdrücke in Globs verwenden. Hier mit erweiterten regulären Ausdrücken:

    ls ~(E:a_[a-z]*_data)

Beachten Sie, dass [a-z]je nach aktuellem Gebietsschema unterschiedliche Übereinstimmungen vorliegen. Es entspricht im Allgemeinen nur den 26 abis zlatin nicht-Umlaut im Clocale. In anderen Gebietsschemata ist die Übereinstimmung im Allgemeinen größer und ergibt nicht immer einen Sinn. Möglicherweise bevorzugen Sie es, einen Buchstaben in Ihrem Gebietsschema zu finden [[:alpha:]].


Können Sie ein Beispiel für [a-z]mehr Übereinstimmungen geben, als die 26 Buchstaben im Gebietsschema C übereinstimmen? Woran ich mich erinnere, als ich dies das letzte Mal angeschaut habe, hatten alle Codierungen, die praktisch in Unix-Varianten verwendet wurden, ISO-646 als Basis (dann wurden die oberen 128 Codes anders verwendet, direkt für Zeichen in Codierungen wie der ISO-8859-X, kombiniert in Kodierungen wie UTF-8 oder die EUC-Familie). Sogar AIX hatte keine EBCDIC-Ländereinstellungen (zumindest so, wie sie mir zur Verfügung standen). Ich erinnere mich, dass ich versucht habe herauszufinden, ob POSIX / UNIX-Standards dies verlangten, aber ich erinnere mich nicht an das Ergebnis.
AProgrammer

1
@AProgrammer, das ist unabhängig von der Codierung, das basiert auf der Sortierreihenfolge (LC_COLLATE). [a-z]schließt im Allgemeinen éoder í(aber nicht notwendigerweise ź) an den Orten ein, an denen der Zeichensatz sie hat, ob der Codepunkt in dieser Codierung zwischen dem von a und z liegt oder nicht. Nur das Gebietsschema C garantiert eine Sortierreihenfolge basierend auf dem Codepunktwert. Weitere Informationen finden Sie in dieser anderen Antwort .
Stéphane Chazelas

Ok, was ich vermisst habe war, dass der Bereich gemäß der aktuellen Kollatierungssequenz interpretiert wurde.
AProgrammer
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.