Bash: como obter o primeiro número que ocorre no conteúdo de uma variável

8

como obter o primeiro número de variáveis

Eu tenho uma variável:

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"

Preciso obter os números:

3000
11
20
Rui F Ribeiro
fonte

Respostas:

7

Com gawk, defina o separador de registros RSpara uma sequência de dígitos. O texto que corresponde ao RSpadrão pode ser recuperado via RT. Adicione 0a RTpara forçá-lo a um número (eliminando assim os zeros iniciais). Saia assim que a primeira instância for impressa

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

Ou aqui está uma solução bash

shopt -s extglob
read -r Z _ <<< "${STR//[^[:digit:] ]/}"
echo ${Z##+(0)}
iruvar
fonte
Agradável. Você gostaria de elaborar?
precisa saber é o seguinte
Eu não entendo. O que estou fazendo de errado (com a versão awk)? gist.github.com/jamiejackson/d92750cc42442a527c6b94499a13bc79
Jamie Jackson
@JamieJackson, certifique-se de que você está executando GNU awk aka gawk
Iruvar
5

Aqui está uma maneira de fazer isso:

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

Teste:

$ 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
fonte
Qual é o objetivo do sedfinal? Parece que antes de entrar no sed já temos o resultado que queremos.
Michael
Não, você precisa do número 2 000011para o qual você precisa remover os zeros à esquerda. Mas você pode simplificar combinando o [1-9][0-9]*que removeria os zeros à esquerda desde o início: echo $STR | grep -o -E '[1-9][0-9]*'
CCH 27/02
2

Se sua implementação de grepnão possuir -oou se você não estiver usando o Bash, faça o seguinte:

printf "%.0f\n" $(printf "%s" "$string"|sed  's/^[^0-9]*//;s/[^0-9].*$//')
Joseph R.
fonte
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
fonte
1
O subscrito deve ser 2 em vez de 1. Mas você realmente não precisa desse complexo de regex. De qualquer forma, falharia se houvesse outros caracteres na string.
Pausado até novo aviso.
2

Eu coloquei suas strings em uma matriz para que ele possa ser facilmente iterado nesta demonstração.

Isso usa a correspondência de expressões regulares incorporada do Bash.

Apenas um padrão muito simples é necessário. É recomendável usar uma variável para manter o padrão em vez de incorporá-lo diretamente no teste de correspondência. É essencial para padrões mais complexos.

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í os colchetes apenas para definir visualmente os números.

Resultado:

[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 obter os números sem os zeros à esquerda, a maneira mais fácil é forçar uma conversão de base 10.

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

Substituindo isso, a saída se parece com o que você solicitou:

3000
11
20
Pausado até novo aviso.
fonte
1

Procure expressões regulares e man grep.

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

e para remover os zeros à esquerda, trate-o como um número:

LIT=$(echo $STR | grep -o [0-9]*)
VAL=$(expr $LIT + 0)
echo $VAL
Sven
fonte
Sua solução falha com as variáveis ​​contém dois números ou o número de preenchimento zero.
cuonglm