Espressione di parentesi (senza intervalli) corrispondente a carattere imprevisto in bash


20

Sto usando bash su Linux. Sto ottenendo un successo dalla seguente dichiarazione if, ma questo non dovrebbe restituire un codice di errore?

if [[  = [⅕⅖⅗] ]] ; then echo yes ; fi

Il quadrato NON eguaglia nessuno dei caratteri, quindi non vedo perché ottengo un codice di successo.

È importante per me mantenere le doppie parentesi nel mio caso.

C'è un altro modo per fare un intervallo in questo scenario o quali altri suggerimenti?


2
Probabilmente una conseguenza di tutti quei personaggi che hanno un ordinamento indefinito nel tuo locale (e quindi ordinano lo stesso). Vedi la discussione in corso, correlata al gruppo di Austin . Cambia la locale in C per risolverlo .
Stéphane Chazelas,

1
Siamo spiacenti, Cnon lo farò qui poiché non sono caratteri a byte singolo. C.UTF-8farebbe dove disponibile.
Stéphane Chazelas,

11
Congratulazioni, sei riuscito a convocare Stéphane brandendo un filo del Gruppo Austin sulla tua prima domanda. Deve valere almeno ⅗ di un Internet. O ⅘ o anche ■ Internet, poiché apparentemente quelli sono gli stessi. Benvenuto in Unix e Linux , e continua a portare domande interessanti.
derobert,

Risposte:


29

Questa è una conseguenza di quei personaggi che hanno lo stesso ordinamento.

Lo noterai anche tu

sort -u << EOF




EOF

restituisce solo una riga.

O quello:

expr  = 

restituisce true (come richiesto da POSIX).

La maggior parte delle versioni locali fornite con i sistemi GNU hanno un numero di caratteri (e persino sequenze di caratteri (sequenze di confronto)) che hanno lo stesso ordinamento. Nel caso di quei ■ ⅕⅖⅗, è perché l'ordine non è definito e quei caratteri il cui ordine non è definito finiscono per avere lo stesso ordinamento nei sistemi GNU. Ci sono personaggi che sono esplicitamente definiti come aventi lo stesso ordinamento come Ș e Ş (sebbene non ci sia una logica reale apparente (per me comunque) o coerenza su come viene fatto).

Questa è la fonte di comportamenti abbastanza sorprendenti e fasulli. Di recente ho sollevato il problema sulla mailing list del gruppo Austin (l'ente dietro POSIX e le specifiche UNIX) e la discussione è ancora in corso dal 03-04-2015.

In questo caso, non è chiaro se [y]corrispondere a xdove xe yordinare lo stesso, ma poiché un'espressione di parentesi deve corrispondere a un elemento di confronto, ciò suggerisce che ilbash comportamento è previsto.

In ogni caso, suppongo [⅕-⅕]o almeno [⅕-⅖]dovrebbe corrispondere .

Noterai che strumenti diversi si comportano diversamente. ksh93 si comporta come bash, GNU grepo sedno. Alcune altre shell hanno comportamenti diversi, alcuni comeyash ancora più buggy.

Per avere un comportamento coerente, è necessario un locale in cui tutti i personaggi si ordinano in modo diverso. La locale C è quella tipica. Tuttavia, il set di caratteri nella locale C sulla maggior parte dei sistemi è ASCII. Sui sistemi GNU, generalmente si ha accesso aC.UTF-8 internazionale che può essere utilizzata invece per lavorare sul carattere UTF-8.

Così:

(export LC_ALL=C.UTF-8; [[  = [⅕⅖⅗] ]])

o l'equivalente standard:

(export LC_ALL=C.UTF-8
 case  in ([⅕⅖⅗]) true;; (*) false; esac)

dovrebbe restituire false.

Un'altra alternativa sarebbe quella di impostare solo LC_COLLATEsu C che funzionerebbe su sistemi GNU, ma non necessariamente su altri in cui potrebbe non riuscire a specificare l'ordinamento del carattere multi-byte.


Una lezione di ciò è che l' uguaglianza non è una nozione così chiara come ci si aspetterebbe quando si tratta di confrontare le stringhe. Uguaglianza potrebbe significare, dal più rigoroso al meno rigoroso.

  1. Lo stesso numero di byte e tutti i componenti byte hanno lo stesso valore.
  2. Lo stesso numero di caratteri e tutti i caratteri sono uguali (ad esempio, fare riferimento allo stesso punto di codice nel set di caratteri corrente).
  3. Le due stringhe hanno lo stesso ordinamento secondo l'algoritmo di confronto delle impostazioni locali (ovvero, a <b né b> a non è vero).

Ora, per 2 o 3, ciò presuppone che entrambe le stringhe contengano caratteri validi. In UTF-8 e alcune altre codifiche, alcune sequenze di byte non formano caratteri validi.

1 e 2 non sono necessariamente equivalenti a causa di ciò o perché alcuni caratteri possono avere più di una possibile codifica. Questo è in genere il caso di codifiche stateful come ISO-2022-JP dove Apossono essere espresse come 41o 1b 28 42 41(1b 28 42 essendo la sequenza per passare a ASCII e puoi inserire tutte quelle che vuoi, che non faranno la differenza), sebbene io non si aspetterebbe che quei tipi di codifica siano ancora in uso e, almeno in genere, gli strumenti GNU non funzionano correttamente con essi.

Attenzione, inoltre, che la maggior parte delle utility non GNU non è in grado di gestire il valore 0 byte (il carattere NUL in ASCII).

Quale di queste definizioni viene utilizzata dipende dall'utilità e dall'implementazione o dalla versione dell'utilità. POSIX non è chiaro al 100% su questo. Nella locale C, tutti e 3 sono equivalenti. Al di fuori di quel YMMV.


Un altro caso comune in cui 1 e 2 differiscono è in Unicode con cose come combinare personaggi.
Gilles 'SO- smetti di essere malvagio' il

@Gilles, combinare i personaggi sono personaggi propri. La combinazione forma un graphem / cell, ma è ancora formata da diversi personaggi. é (U + 00E9) ed é (e seguito da U + 0301) sono lo stesso graphem, ma due diverse sequenze di caratteri (almeno dal punto di vista delle API POSIX). Di 1 e 2, sarebbero diversi. A partire da 3, potrebbero considerare lo stesso se U + 0301 avesse tutti i suoi pesi di collazione impostati su "IGNORE", ma in genere non è così poiché si vuole generalmente decidere l'ordine dei segni diacritici.
Stéphane Chazelas,

Di solito è desiderabile considerare ée essere la stessa stringa, ma non e. La nozione di ordine di confronto di POSIX è raramente corretta, è troppo fortemente basata sui caratteri e non tiene conto dei modi più comuni di ordinare le stringhe (ad esempio i dizionari francesi non usano un ordine lessicografico per ordinare le parole: fanno un primo passaggio lessicografico con accenti ignorati e quindi usa gli accenti per decidere i legami).
Gilles 'SO- smetti di essere malvagio' il

@Gilles, sì. Ecco perché direi che quei personaggi che hanno lo stesso ordinamento (intenzionale) in locali glibc hanno poco senso. L'é vs é di solito viene affrontata effettuando prima una trasformazione sulle stringhe come la decomposizione canonica (simile alla conversione in minuscolo prima quando si desidera eseguire l'ordinamento / abbinamento senza distinzione tra maiuscole e minuscole). Vedi anche la guida ICU per qualche buon riferimento sull'argomento.
Stéphane Chazelas,

@Gilles, i pesi dell'algoritmo di confronto delle impostazioni locali POSIX possono eseguire l'ordinamento dei dizionari in francese. Ecco come funzionano i pesi. Un primo passaggio usa i pesi primari (dove e ed é (ed E ed É) hanno lo stesso e l'accento acuto combinato viene ignorato) un secondo passaggio (se uguale) controlla gli accenti, una capitalizzazione di 3 ° passaggio ...
Stéphane Chazelas

-3

Stai sbagliando =e ==non sono la stessa cosa.

Prova questi esempi:

if [[ "■" == "[⅕⅖⅗]" ]] ; then echo yes ; else echo no ; fi

if [[ "1" == "1" ]] ; then echo yes ; else echo no ; fi

if [[ "■" == "■" ]] ; then echo yes ; else echo no ; fi

1
Non è vero. POSIX specifica che l'operatore =deve essere usato per verificare l'uguaglianza. Il problema sono le virgolette mancanti, non l'operatore.
scai,

1
man bashDice anche nella [[sezione: "L'operatore = equivale a ==."
michas,

1
@scai, POSIX non specifica l' [[...]]operatore. E = e == sono gli stessi nelle shell dove è stato implementato (ksh / bash / zsh) e per la corrispondenza dei modelli, non l'uguaglianza.
Stéphane Chazelas,

Quando si confronta con un modello, il modello non deve essere citato, altrimenti viene preso come una stringa letterale, quindi il "no" nel primo test.
xhienne,
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.