2010-07-19 18 views
7

Sono nuovo di UNIX, avendo solo iniziato al lavoro oggi, ma con esperienza con Java, e hanno il seguente codice:Controllo una stringa per vedere se contiene caratteri numerici in UNIX

#/bin/bash 
echo "Please enter a word:" 
read word 
grep -i $word $1 | cut -d',' -f1,2 | tr "," "-"> output 

questo funziona bene, ma quello che ora devo fare è controllare quando la parola viene letta, che non contiene nient'altro che lettere e se ha caratteri numerici nella stampa "Input non valido!" messaggio e chiedere loro di inserirlo di nuovo. Ho assunto espressioni regolari con un'istruzione if se fosse il modo semplice per farlo, ma non riesco a capire come usarle in UNIX come sono abituato all'applicazione Java di loro. Qualsiasi aiuto con questo sarebbe molto apprezzato, dato che non sono riuscito a trovare aiuto durante la ricerca come tutte le soluzioni con espressioni regolari in linux che ho trovato affrontate solo se era tutto numerico o no.

risposta

17

Ancora un altro approccio. Grep esce con 0 se viene trovata una corrispondenza, in modo da poter testare il codice di uscita:

echo "${word}" | grep -q '[0-9]' 
if [ $? = 0 ]; then 
    echo 'Invalid input' 
fi 

Questo è /bin/sh compatibili.


Incorporando Daenyth e John di suggerimenti, questo diventa

if echo "${word}" | grep '[0-9]' >/dev/null; then 
    echo 'Invalid input' 
fi 
+3

'-q' per grep non è portabile al di fuori di GNU.Se vuoi una portabilità completa (l'unica ragione per usare mai sh), usa '>/dev/null 2> & 1' – Daenyth

+0

+1, Questa è una soluzione davvero UNIX, semplice e pulita. – Anders

+0

@Daenyth hai assolutamente ragione, e l'ho fatto anche quando l'ho provato sul mio sistema, poi ho aggiunto il '-q' quando ho postato la mia risposta. Sembra che sia stato GNU solo per troppo tempo. –

0

One portatile (assumendo bash> = 3) modo per farlo è quello di rimuovere tutti i numeri e test per la lunghezza:

#!/bin/bash 
read -p "Enter a number" var 
if [[ -n ${var//[0-9]} ]]; then 
    echo "Contains non-numbers!" 
else 
    echo "ok!" 
fi 

Venendo da Java, è importante notare che bash ha nessun vero concetto di oggetti o tipi di dati. Tutto è una stringa e le strutture dati complesse sono dolorose nel migliore dei casi.

Per ulteriori informazioni su cosa ho fatto e altre funzioni correlate, google per la manipolazione delle stringhe bash.

+1

Supponendo kitty bash? È crudele. – MikeD

7

L'operatore doppia staffa è una versione estesa del comando test che supporta espressioni regolari tramite l'operatore =~:

#!/bin/bash 

while true; do 
    read -p "Please enter a word: " word 
    if [[ $word =~ [0-9] ]]; then 
     echo 'Invalid input!' >&2 
    else 
     break 
    fi 
done 

Questa è una caratteristica specifica-bash. Bash è una shell più recente che non è disponibile su tutti i tipi di UNIX - anche se per "più recente" intendo "sviluppato solo di recente nell'era del tubo post-vuoto" e "non tutti i sapori di UNIX" intendo reliquie come vecchie versioni di Solaris e HP-UX.

A mio parere questa è l'opzione più semplice e bash è molto portatile in questi giorni, ma se essere portatili per vecchi UNIX è in realtà importante, allora è necessario utilizzare le risposte sh-compatibili degli altri poster. sh è la shell più comune e più ampiamente supportata, ma il prezzo che si paga per la portabilità sta perdendo cose come =~.

3

Se si sta tentando di scrivere codice shell portatile, le opzioni per la manipolazione delle stringhe sono limitate. È possibile utilizzare shell glob pattern (che sono molto meno espressivo di espressioni regolari) nella case costrutto:

export LC_COLLATE=C 
read word 
while 
    case "$word" in 
    *[!A-Za-z]*) echo >&2 "Invalid input, please enter letters only"; true;; 
    *) false;; 
    esac 
do 
    read word 
done 

EDIT: impostazione LC_COLLATE è necessaria perché nella maggior parte non C locali, intervalli di caratteri come A-Z don' t avere il significato "ovvio". Suppongo tu voglia solo lettere ASCII; se si desidera anche lettere con segni diacritici, non modificare LC_COLLATE e sostituire A-Za-z per [:alpha:] (quindi l'intero motivo diventa *[![:alpha:]]*).

Per le espressioni regolari complete, consultare il comando expr. EDIT: Si noti che expr, come molti altri strumenti di shell di base, presenta problemi con alcune stringhe speciali; i caratteri z di seguito impediscono di interpretare $word come parole riservate da expr.

export LC_COLLATE=C 
read word 
while expr "z$word" : 'z[A-Za-z]*$' >/dev/null; then 
    echo >&2 "Invalid input, please enter letters only" 
    read word 
fi 

Se il target solo versioni recenti abbastanza di bash, ci sono altre opzioni, come ad esempio l'operatore del =~[[ ... ]] comandi condizionali.

Si noti che l'ultima linea ha un bug, il primo comando dovrebbe essere

grep -i "$word" "$1" 

le virgolette sono perché un po 'contro-intuitivo, "$foo" significa “il valore della variabile chiamata foo”, mentre pianura $foo mezzi “ prendi il valore di foo, dividilo in parole separate dove contiene spazi bianchi e considera ogni parola come uno schema di globbing e prova ad espanderlo ". (Infatti se hai già controllato che $word contenga solo lettere, lasciare le virgolette non farà alcun danno, ma ci vuole più tempo a pensare a questi casi speciali che a mettere le virgolette tutte le volte.)

+0

Il caso elencato non funziona per input non numerico non ASCII. – Daenyth

+0

@Daenyth: true, tutte le soluzioni che usano 'A-Za-z' assumono un locale ASCII. Quindi aggiungo una nota a piè di pagina: se si desidera consentire tutte le lettere nella propria localizzazione (comprese le lettere con segni diacritici), sostituire 'A-Za-z' con' [: alpha:] 'ovunque (' case', 'expr') , 'grep', ...) (sì, avrai parentesi tra parentesi). Se vuoi solo lettere ASCII, metti 'export LC_COLLATE = C' vicino all'inizio del tuo script. – Gilles

+0

La soluzione più semplice è solo invertirla - verifica che contenga '[^ 0-9]'. Una lista bianca è più facile di una lista nera. – Daenyth

0

Giocando intorno con le classi di espansione dei parametri e dei personaggi Bash:

# cf. http://wiki.bash-hackers.org/syntax/pe 

word="abc1def" 
word="abc,def" 
word=$'abc\177def' 
# cf. http://mywiki.wooledge.org/BashFAQ/058 (no NUL byte in Bash variable) 
word=$'abc\000def' 
word="abcdef" 

(
set -xv 
[[ "${word}" != "${word/[[:digit:]]/}" ]] && echo invalid || echo valid 
[[ -n "${word//[[:alpha:]]/}" ]] && echo invalid || echo valid 
) 
1

Ancora un altro modo (abbastanza) portatile per farlo. ..

if test "$word" != "`printf "%s" "$word" | tr -dc '[[:alpha:]]'`"; then 
    echo invalid 
fi 
0

Le risposte di tutti sembrano essere basate sul fatto che i soli caratteri non validi sono numeri. Le domande iniziali affermano che è necessario verificare che la stringa contenga "nient'altro che lettere".

Penso che il modo migliore per farlo è

nonalpha=$(echo "$word" | sed 's/[[:alpha:]]//g') 
if [[ ${#nonalpha} -gt 0 ]]; then 
    echo "Invalid character(s): $nonalpha" 
fi 

Se hai trovato questa pagina alla ricerca di un modo per rilevare i caratteri non numerici nella stringa di sostituire [[(come ho fatto io!): Alpha: ]] con [[: digit:]].

Problemi correlati