Sensibilità del case in globbing a staffa quadrata


10

Normalmente, bash globbing è case sensitive:

$ echo c*
casefix.pike cdless chalices.py charconv.py chocolate.pike circum.py clip.pike cpustats.pike crop.pike cwk2txt.py
$ echo C*
CarePackage.md ChocRippleCake.md Clips

L'uso delle parentesi quadre non sembra cambiare questo:

$ echo [c]*
casefix.pike cdless chalices.py charconv.py chocolate.pike circum.py clip.pike cpustats.pike crop.pike cwk2txt.py
$ echo [C]*
CarePackage.md ChocRippleCake.md Clips

Non cambia ancora se viene utilizzato un trattino:

$ echo [c-c]*
casefix.pike cdless chalices.py charconv.py chocolate.pike circum.py clip.pike cpustats.pike crop.pike cwk2txt.py
$ echo [C-C]*
CarePackage.md ChocRippleCake.md Clips

Ma le lettere sono intervallate:

$ echo [B-C]*
CarePackage.md casefix.pike cdless chalices.py charconv.py chocolate.pike ChocRippleCake.md circum.py clip.pike Clips cpustats.pike crop.pike cwk2txt.py
$ echo [b-c]*
beehive-anthem.txt bluray2mkv.pike branch branchcleanup.pike burdayim.pike casefix.pike cdless chalices.py charconv.py chocolate.pike circum.py clip.pike cpustats.pike crop.pike cwk2txt.py

Ciò suggerisce che il trattino sta usando un ordine locale, "AaBbCcDd". Quindi: c'è un modo per glob per tutti i file che iniziano con una lettera maiuscola?


3
Nota anche il gotcha che [AZ] corrisponde a tutte le lettere minuscole tranne 'z'!
PJTraill,

Risposte:


12

Nella versione 4.3 e successive di bash, c'è un'opzione shopt chiamata globasciiranges:

Secondo le pagine man di shopt gnu :

globasciiranges
Se impostato, le espressioni di intervallo utilizzate nelle espressioni di parentesi di corrispondenza dei pattern (vedere Corrispondenza dei pattern) si comportano come nelle impostazioni locali C tradizionali quando si eseguono i confronti. In altre parole, la sequenza di confronto delle impostazioni locali correnti non viene presa in considerazione, quindi "b" non verrà confrontato tra "A" e "B" e i caratteri ASCII maiuscoli e minuscoli verranno raccolti insieme.

Di conseguenza puoi farlo

$ shopt -s globasciiranges 
$ echo [A-Z]*

Utilizzare shopt -uper disabilitare.

Un altro modo è cambiare le impostazioni locali in C. È possibile farlo temporaneamente usando una subshell:

$ ( LC_ALL=C ; printf '%s\n' [A-Z]*; )

Otterrai i risultati di cui hai bisogno e, al termine della shell secondaria, la locale della shell principale rimane invariata rispetto a prima.

Un'altra alternativa è invece quella di [A-Z]utilizzare l'espansione del controvento {A..Z}insieme nullgloball'opzione bash shopt.

Abilitando l' nullglobopzione, se un modello non corrisponde durante l'espansione del nome percorso, viene restituita una stringa nulla anziché il modello stesso.
Di conseguenza questo funzionerà come previsto:

$ shopt -s nullglob;printf '%s\n' {A..Z}*

2
Perfetto grazie. Non posso usarlo [[:upper:]]perché in realtà voglio solo una parte dell'alfabeto, ma funziona.
Rosuav,

1
@rosuav Benvenuti. Controlla anche la sub shell alternativa.
George Vasiliou,

"Se abilitato equivale a C locale" - vuoi dire che influenza il locale usato per il globbing e nient'altro? (Un link di riferimento sarebbe stato utile - il migliore che posso trovare è gnu.org/software/bash/manual/html_node/Pattern-Matching.html , ma avrei preferito un elenco di tutte le opzioni di shell, ma mancano globasciiranges da gnu.org/software/bash/manual/html_node/… ; anche la domanda unix.stackexchange.com/questions/227070/… gestisce ampiamente questo problema.) Anche dalla versione 4.3.
PJTraill,

@PjTrail Guarda la mia modifica con un link di riferimento a tutte le opzioni di shopt. Inoltre puoi correre man bashnel tuo terminale e cercare (usando /) i globasciirange.
George Vasiliou,

Non LC_ALL=C printf '%s\n' [A-Z]*funzionerebbe con la tua seconda soluzione - senza una sottoshell? A proposito: c'è un errore di battitura:, nullblogma sono troppi pochi caratteri per me per correggerlo.
Joe,

5

Puoi scrivere tutte le lettere maiuscole come:

[ABCDEFGHIJKLMNOPQRSTUVWXYZ]*

oppure use può usare la classe di caratteri con nome [:upper:]per rappresentare tutte le lettere maiuscole nel tuo attuale locale:

[[:upper:]]*

Come avrai notato, mentre usi l'intervallo come [B-C]la maiuscola e la minuscola per lo stesso carattere alfabetico, vengono sistemati adiacenti (in base all'ordine di confronto di locale).


3

L'inclusione di caratteri "non intuitivi" negli intervalli di caratteri, come l'inclusione di lettere minuscole in un intervallo i cui confini sono lettere maiuscole, è dovuta LC_COLLATEall'impostazione della locale. LC_COLLATEsi suppone che indichi l'ordinamento, ma fa un cattivo lavoro (l'ordinamento delle stringhe è più complesso di quello che le localizzazioni possono fare) e si sta meglio senza di esso. Consiglio di rimuovere LC_COLLATEdalle impostazioni locali. Se si sta impostando LANG, o LANGUAGE, non farlo e impostare solo quelle che ti servono: LC_CTYPE, LC_MESSAGES, LC_TIME.

Per ulteriori informazioni sulle impostazioni locali, vedere Cosa devo impostare le impostazioni locali e quali sono le implicazioni per farlo? e imposta LC_ * ma non LC_ALL

Per ottenere risultati affidabili in uno script indipendentemente dalle impostazioni dell'utente, impostare LC_ALL=C.


0

Impostato:

shopt -u nocaseglob

Dalla pagina man di bash:

>     nocaseglob
>         If  set,  bash matches filenames in a case-insensitive
>         fashion when performing pathname expansion (see Pathname
>          Expansion above).

Se imposti "globasciiranges" non so cosa accadrà ai personaggi non ascii come utf-8


0

echo [cC] * dovrebbe fare quello che vuoi, allo stesso modo [A-Za-z] *

Sono qui perché il globbing sul mio sistema ha appena smesso di fare distinzione tra maiuscole e minuscole, quindi molti dei miei script non funzionano più come dovrebbero :-(


Questo è l'opposto di quello che sto vedendo. Ma controlla le altre risposte per suggerimenti.
Rosuav,
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.