Bash: come ottenere il primo numero che si verifica nel contenuto di una variabile


8

come ottenere il primo numero di variabili

Ho una variabile:

STR="My horse weighs 3000 kg but the car weighs more"
STR="Maruska found 000011 mushrooms but only 001 was not with meat"
STR="Yesterday I almost won the lottery 0000020 CZK but in the end it was only 05 CZK"

Ho bisogno di ottenere i numeri:

3000
11
20

Risposte:


7

Con gawk, imposta il separatore record RSsu una sequenza di cifre. Il testo corrispondente al RSmodello può essere recuperato tramite RT. Aggiungi 0a RTper forzarlo su un numero (facendo così cadere gli zeri iniziali). Esci non appena viene stampata la prima istanza

awk -v RS=[0-9]+ '{print RT+0;exit}' <<< "$STR"

Oppure ecco una soluzione bash

shopt -s extglob
read -r Z _ <<< "${STR//[^[:digit:] ]/}"
echo ${Z##+(0)}

Bello. Ti interessa elaborare?
jasonwryan,

Non capisco Cosa sto facendo di sbagliato (con la versione awk)? gist.github.com/jamiejackson/d92750cc42442a527c6b94499a13bc79
Jamie Jackson

@JamieJackson, assicurati di eseguire GNU awk aka gawk
iruvar

5

Ecco un modo per farlo:

echo $STR | grep -o -E '[0-9]+' | head -1 | sed -e 's/^0\+//'

Test:

$ STR="My horse weighs 3000 kg but the car weighs more"
$ echo $STR | grep -o -E '[0-9]+' | head -1 | sed -e 's/^0\+//'
3000

$ STR="Maruska found 000011 mushrooms but only 001 was not with meat"
$ echo $STR | grep -o -E '[0-9]+' | head -1 | sed -e 's/^0\+//'
11

$ STR="Yesterday I almost won the lottery 0000020 CZK but in the end it was only 05 CZK"
$ echo $STR | grep -o -E '[0-9]+' | head -1 | sed -e 's/^0\+//'
20

Qual è lo scopo di sedalla fine? Sembra che prima di entrare in sed abbiamo già il risultato che vogliamo.
Michael,

No, hai il numero 2 000011per il quale devi rimuovere gli zeri delle derivazioni. Ma potresti semplificare abbinando [1-9][0-9]*che rimuove gli zeri iniziali dall'inizio: echo $STR | grep -o -E '[1-9][0-9]*'
CCH

2

Se la tua implementazione di grepnon ha -oo se non stai usando Bash, puoi fare quanto segue:

printf "%.0f\n" $(printf "%s" "$string"|sed  's/^[^0-9]*//;s/[^0-9].*$//')

2
#!/bin/bash

string="My horse weighs 3000 kg but the car weighs more"

if [[ $string =~ ^([a-zA-Z\ ]*)([0-9]*)(.*)$ ]]
then
    echo ${BASH_REMATCH[1]}
fi  

1
Il pedice dovrebbe essere 2 invece di 1. Ma non hai davvero bisogno di quel complesso di regex. Avrebbe fallito comunque se ci fossero altri caratteri nella stringa.
In pausa fino a nuovo avviso.

2

Ho messo le tue stringhe in un array in modo che possa essere facilmente ripetuto per questa dimostrazione.

Questo utilizza la corrispondenza delle espressioni regolari incorporata di Bash.

È richiesto solo un modello molto semplice. Si consiglia di utilizzare una variabile per contenere il modello invece di incorporarlo direttamente nel match test. È essenziale per schemi più complessi.

str[0]="My horse weighs 3000 kg but the car weighs more"
str[1]="Maruska found 000011 mushrooms but only 001 was not with meat"
str[2]="Yesterday I almost won the lottery 0000020 CZK but in the end it was only 05 CZK"

patt='([[:digit:]]+)'

for s in "${str[@]}"; do [[ $s =~ $patt ]] && echo "[${BASH_REMATCH[1]}] - $s"; done

Ho incluso le parentesi quadre solo per impostare visivamente i numeri.

Produzione:

[3000] - My horse weighs 3000 kg but the car weighs more
[000011] - Maruska found 000011 mushrooms but only 001 was not with meat
[0000020] - Yesterday I almost won the lottery 0000020 CZK but in the end it was only 05 CZK

Per ottenere i numeri senza gli zeri iniziali, il modo più semplice è forzare una conversione in base 10.

echo "$(( 10#${BASH_REMATCH[1]} ))"

Sostituendo quello, l'output assomiglia a quello che hai richiesto:

3000
11
20

1

Cerca espressioni regolari e man grep.

echo $STR | grep -o [0-9]*

e per rimuovere gli zeri iniziali, trattalo come un numero:

LIT=$(echo $STR | grep -o [0-9]*)
VAL=$(expr $LIT + 0)
echo $VAL

La tua soluzione ha esito negativo con le variabili contiene due numeri o il numero di riempimento zero.
cuonglm
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.