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.