Ricerca di sottostringa senza distinzione tra maiuscole e minuscole in uno script di shell [chiuso]


22

Come posso scrivere uno script di shell che eseguirà una corrispondenza di sottostringa senza distinzione tra maiuscole e minuscole dell'output del comando?


grep -ipuò essere?
Ramesh,

Come lo inserirò nella mia sceneggiatura? Mi dispiace se questa è una domanda per principianti. Ho appena iniziato a studiare Linux perché ne ho bisogno per il mio internato. Grazie!
Miguel Roque,

1
Quello che stai chiedendo è lo script di shell - "linux" non è un linguaggio di programmazione, è un kernel del sistema operativo. La shell più comunemente usata con Linux è bash, che è un superset dello standard unixsh . Potresti iniziare guardando uno di questi: | 1 | | 2 | - solo per capire qual è il contesto reale.
Riccioli d'oro,

1
Questa domanda ora sembra abbastanza chiara e corrisponde alle linee guida del centro assistenza. Può per favore essere aperto a beneficio di altri?
BobDoolittle

2
Non vedo la confusione perché questa domanda non è chiara. Cosa devo aggiungere perché sia ​​chiaro?
Miguel Roque,

Risposte:


11

Innanzitutto ecco un semplice script di esempio che non ignora il caso:

#!/bin/bash
if [ $(echo hello) == hello ]; then
    echo it works
fi

Prova a cambiare la stringa ciao a destra e non dovrebbe più echeggiare it works. Prova a sostituire echo hellocon un comando di tua scelta. Se vuoi ignorare il caso e nessuna stringa contiene un'interruzione di riga, puoi usare grep:

#!/bin/bash
if echo Hello | grep -iqF hello; then
    echo it works
fi

La chiave qui è che stai eseguendo il piping di un comando di output grep. L' ifistruzione verifica lo stato di uscita del comando più a destra in una pipeline, in questo caso grep. Grep esce con successo se e solo se trova una corrispondenza.

L' -iopzione di grep dice di ignorare il caso.
L' -qopzione dice di non emettere output e uscire dopo la prima corrispondenza.
L' -Fopzione dice di trattare l'argomento come una stringa piuttosto che un'espressione regolare.

Si noti che il primo esempio utilizza che consente confronti diretti e vari operatori utili. Il secondo modulo esegue semplicemente i comandi e verifica il loro stato di uscita.[ expression ]


Non capisco perché Gilles abbia ritenuto necessario cambiare il codice che ho contribuito. Non ha rotto nulla, ma ha funzionato bene. In questo esempio non sono necessarie le virgolette doppie, ma sono importanti se l'output contiene spazi. E == funziona esattamente come = perché sh è in realtà bash su Linux. L'originale Bourne Shell è ormai lontana da questo momento. Non credo che nemmeno Solaris lo spedisca più. Sebbene non sia necessario in questo esempio, concordo sul fatto che le doppie virgolette sono probabilmente una buona pratica, ma lo è anche "==" a mio avviso, per mantenere chiaramente il compito e il confronto separati.
BobDoolittle,

Aspetta, quindi si può modificare un post? Non lo sapevo.
Miguel Roque,

Con sufficiente reputazione, sì. Spero che qualcuno con una grande reputazione ci pensi due volte prima di apportare modifiche inutili, in particolare per programmare in questo forum. unix.stackexchange.com/help/privileges
BobDoolittle

@BobDoolittle In alcuni casi può fare la differenza, ma non con la tua configurazione - è bene saperlo.

2
Si noti che in pratica non si tratta solo della shell Bourne. ==non è POSIX. shnon è bashsu tutti i sistemi basati su Linux. ==non è supportato da ash(su cui shsi basa almeno il molti dei derivati ​​BSD e Debian) o posh, e deve essere citato in zsh. Non ha senso raddoppiare il =. [è un comando per il test. Non c'è bisogno di chiarire tra incarico e confronto qui. Questo è diverso (( a == b ))vs (( a = b)). L'uso ==in uno script che inizia con #! /bin/shè sbagliato. Se si assume ksho bashsintassi, aggiornare di #!conseguenza.
Stéphane Chazelas,

49

È possibile eseguire la sottostringa senza distinzione tra maiuscole e minuscole in modo nativo bashutilizzando l'operatore regex =~se si imposta l' nocasematchopzione shell. Per esempio

s1="hElLo WoRlD"
s2="LO"

shopt -s nocasematch

[[ $s1 =~ $s2 ]] && echo "match" || echo "no match"
match

s1="gOoDbYe WoRlD"
[[ $s1 =~ $s2 ]] && echo "match" || echo "no match"
no match

6
lol! punti per conoscenza oscura del guscio.
BobDoolittle,

2
Questa opzione influenza anche l'operatore di corrispondenza semplice. [[ XYZ == xyz ]] && echo "match"=>match
aggiunto il

7

Per una ricerca stringa sensibile al maiuscolo / minuscolo del valore della variabile needlenel valore della variabile haystack:

case "$haystack" in
  *"$needle"*) echo "present";
  *) echo "absent";
esac

Per una ricerca di stringhe senza distinzione tra maiuscole e minuscole, converti entrambi nello stesso caso.

uc_needle=$(printf %s "$needle" | tr '[:lower:]' '[:upper:]' ; echo .); uc_needle=${uc_needle%.}
uc_haystack=$(printf %s "$haystack" | tr '[:lower:]' '[:upper:]' ; echo .); uc_haystack=${uc_haystack%.}
case "$uc_haystack" in
  *"$uc_needle"*) echo "present";;
  *) echo "absent";;
esac

Nota che i trcoreutils in GNU non supportano le localizzazioni multibyte (es. UTF-8). Per lavorare con le versioni locali multibyte, usa invece awk. Se hai intenzione di usare awk, puoi farlo fare il confronto delle stringhe e non solo la conversione.

if awk 'BEGIN {exit !index(toupper(ARGV[2]), toupper(ARGV[1]))}' "$needle" "$haystack"; then
  echo "present"
else
  echo "absent"
fi

Il trda BusyBox non supporta la sintassi; puoi usare invece. BusyBox non supporta impostazioni locali non ASCII.[:CLASS:]tr a-z A-Z

In bash (ma non sh), versione 4.0+, esiste una sintassi integrata per la conversione dei casi e una sintassi più semplice per la corrispondenza delle stringhe.

if [[ "${haystack^^}" = *"${needle^^}"* ]]; then
  echo "present"
else
  echo "absent"
esac

Mi rendo conto che ha un paio d'anni, ma tutto ciò printf | trmi fa girare la testa. Ove possibile, mantieni la tua invocazione di comandi al minimo ... data una variabile v, puoi realizzare la stessa cosa usando v=$(tr '[:lower:]' '[:upper:]' <<<$v). Per coloro che non l'hanno mai visto prima, <<<è essenzialmente una "variabile qui" come l'uso di <<EOFè per un documento qui. Non farlo printfo echomeno che tu non debba assolutamente farlo.
Sarà l'

@Will Funziona solo con shell che hanno l' <<<operatore: ksh, bash, zsh, ma non semplicemente sh. Ed è abbastanza vicino al piping printfin termini di come funziona: c'è lo stesso numero di chiamate forke execve(supponendo che printfsia integrato, come nel caso delle shell più comuni); la differenza è che <<<crea un file temporaneo anziché utilizzare una pipe. <<<è conveniente digitare ma non un miglioramento delle prestazioni.
Gilles 'SO- smetti di essere malvagio' l'
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.