Perché l'asterisco [az] corrisponde ai numeri?


13

Ho 3 directory al percorso attuale.

$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:

Mi aspettavo che l'ultimo comando LS corrispondesse solo a_clean_data. Perché corrispondeva anche a quello contenente 0?

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

2
Vedi questa domanda per ulteriori informazioni sulla differenza tra un'espressione regolare e un glob.
Terdon

4
Quindi il fatto che a_*_datacorrisponda a uno di questi file non ti ha sorpreso?
Cthulhu,

@Cthulhu mi hai preso!
user13107

Risposte:


29

La [a-z]parte non è quella che corrisponde al numero; è il *. Potresti confondere il gorgoglio delle shell e le espressioni regolari .

Strumenti come grepaccettare vari tipi di regex (di base per impostazione predefinita, -Eper esteso, -Pper perl regex )

Ad esempio ( -vinverte la partita)

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

Se vuoi usare un regex bash, ecco un esempio su come testare se la variabile $refè un numero intero:

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



21

Quindi il problema è: perché a_[a-z]*_datacorrisponde a_clean_0db_data?

Questo può essere suddiviso in quattro parti:

  • a_corrisponde all'inizio di a_clean_0db_data, lasciando clean_0db_dataper essere abbinato

  • [a-z]corrisponde a qualsiasi personaggio nell'intervallo a-z(ad es. c), lasciando lean_0db_datada abbinare

  • * corrisponde a qualsiasi numero di caratteri, ad es lean_0db

  • _data corrisponde al finale _data

Nelle espressioni regolari, [a-z]*significherebbe un numero qualsiasi di caratteri (incluso zero) nell'intervallo di a..z , ma hai a che fare con il gorgogliamento della shell, non con le espressioni regolari.

Se vuoi espressioni regolari, alcune findimplementazioni hanno un -regexpredicato per questo:

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

È -maxdepthqui solo per limitare i risultati della ricerca alla cartella in cui ci si trova. L' espressione regolare corrisponde all'intero nome file, quindi ho aggiunto a ^.*/per abbinare la parte del percorso


11

*nei modelli shell corrisponde a 0 o più caratteri. Non deve essere confuso con l' *operatore dell'espressione regolare che significa 0 o più dell'atomo precedente .

Non esiste un equivalente di regexp *nei modelli di shell di base. Tuttavia, varie shell hanno estensioni per questo.

  • kshha *(something):

    ls a_*([a-z])_data
  • puoi avere lo stesso bashcon shopt -s extglobo zshcon setopt kshglob:

    shopt -s extglob
    ls a_*([a-z])_data
  • In zshcon extendedglobabilitato, #è equivalente a regexp *:

    setopt extendedglob
    ls a_[a-z]#_data
  • Nelle versioni recenti di ksh93, puoi anche usare espressioni regolari nei globs. Qui con espressioni regolari estese :

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

Nota che [a-z]corrisponde a cose diverse a seconda della locale corrente. Si abbina generalmente solo le 26 adi zlettere non accentate latini nel Clocale. In altri locali, generalmente corrisponde di più e non ha sempre senso. Per abbinare una lettera nella tua lingua, potresti preferire [[:alpha:]].


Potresti dare un esempio di [a-z]corrispondenza maggiore rispetto alle 26 lettere corrispondenti nella locale C? Quello che ricordo da quando l'ho visto l'ultima volta, tutte le codifiche praticamente utilizzate nelle varianti Unix avevano ISO-646 come base (quindi i 128 codici superiori erano usati in modo diverso, direttamente per i caratteri nelle codifiche come ISO-8859-X, combinati in codifiche come UTF-8 o la famiglia EUC). Perfino AIX non aveva localizzazioni EBCDIC (almeno per quanto disponibili per me). Ricordo di aver provato a scoprire se gli standard POSIX / UNIX lo richiedevano, ma non ricordo il risultato.
AProgrammer,

1
@AProgrammer, indipendente dalla codifica, basato sull'ordinamento (LC_COLLATE). [a-z]generalmente include éo í(ma non necessariamente ź) nei locali in cui sono presenti i set di caratteri, indipendentemente dal fatto che il punto di codice in quella codifica sia compreso tra quello di a e z o meno. Solo la locale C garantisce un ordinamento basato sul valore del punto di codice. Vedi questa altra risposta per maggiori dettagli.
Stéphane Chazelas,

Ok, quello che mi mancava era che l'intervallo era interpretato secondo l'attuale sequenza di confronto.
AProgrammer,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.