Bash: cómo obtener el primer número que ocurre en el contenido de una variable

8

cómo obtener el primer número de variables

Tengo una variable:

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"

Necesito obtener los números:

3000
11
20
Rui F Ribeiro
fuente

Respuestas:

7

Con gawk, establezca el separador de registros RSen una secuencia de dígitos. El texto que coincide con el RSpatrón se puede recuperar a través de RT. Agregue 0a RTpara forzarlo a un número (eliminando así los ceros iniciales). Salga tan pronto como se imprima la primera instancia

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

O aquí hay una solución bash

shopt -s extglob
read -r Z _ <<< "${STR//[^[:digit:] ]/}"
echo ${Z##+(0)}
iruvar
fuente
Agradable. ¿Te importa elaborar?
jasonwryan
No lo entiendo ¿Qué estoy haciendo mal (con la versión awk)? gist.github.com/jamiejackson/d92750cc42442a527c6b94499a13bc79
Jamie Jackson
@JamieJackson, asegúrate de estar ejecutando GNU awk aka gawk
iruvar
5

Aquí hay una forma de hacerlo:

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

Prueba:

$ 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
Cuonglm
fuente
¿Cuál es el propósito de sedal final? Parece que antes de que entre en sed ya tenemos el resultado que queremos.
Michael
No, tiene el # 2 000011para el cual debe eliminar los ceros iniciales. Pero podría simplificar haciendo coincidir [1-9][0-9]*lo que eliminaría los ceros iniciales desde el principio: echo $STR | grep -o -E '[1-9][0-9]*'
CCH
2

Si su implementación de grepno tiene -oo si no está usando Bash, puede hacer lo siguiente:

printf "%.0f\n" $(printf "%s" "$string"|sed  's/^[^0-9]*//;s/[^0-9].*$//')
Joseph R.
fuente
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  
philippe
fuente
1
El subíndice debe ser 2 en lugar de 1. Pero realmente no necesita ese complejo de una expresión regular. De todos modos, fallaría si hubiera otros caracteres en la cadena.
Pausado hasta nuevo aviso.
2

He puesto sus cadenas en una matriz para que se pueda iterar fácilmente para esta demostración.

Esto utiliza la coincidencia de expresiones regulares incorporada de Bash.

Solo se requiere un patrón muy simple. Se recomienda utilizar una variable para mantener el patrón en lugar de incorporarlo directamente en la prueba de coincidencia. Es esencial para patrones más complejos.

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

Incluí los corchetes solo para resaltar visualmente los números.

Salida:

[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

Para obtener los números sin los ceros a la izquierda, la forma más fácil es forzar una conversión de base 10.

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

Sustituyendo eso, la salida se parece a lo que solicitó:

3000
11
20
Pausado hasta nuevo aviso.
fuente
1

Busque expresiones regulares y man grep.

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

y para eliminar los ceros iniciales, trátelo como un número:

LIT=$(echo $STR | grep -o [0-9]*)
VAL=$(expr $LIT + 0)
echo $VAL
Sven
fuente
Su solución falla con variables que contienen dos números o el relleno de número cero.
Cuonglm