While loop usando um contador utilizando a entrada do usuário de um inteiro

2

Eu estou trabalhando em um script e eu tenho um tempo em que eu quero levar a entrada do usuário e usar como um valor inteiro com um contador assim:

read -p "How many bytes would you like you replace :> " $numOfBytes
echo "$numOfBytes bytes to replace"
while [ $counter -le $numOfBytes ]
do
    echo "testing counter value = $counter"
    let $counter++
done

No meu entender, ele não funciona atualmente porque está tomando a variável numOfBytes como uma string.

Preciso converter a string para um int de alguma forma? É possível fazer algo assim? Existe uma alternativa?

    
por 0siris 15.05.2018 / 19:10

3 respostas

5

Você deseja ler um inteiro e, em seguida, fazer um loop de 1 a esse inteiro, imprimindo o número em cada iteração:

#!/bin/bash

read -p 'number please: ' num

for (( i = 1; i <= num; ++i )); do
    printf 'counter is at %d\n' "$i"
done 

Observe como o $ não é usado ao ler o valor. Com $var você obtém o valor da variável var , mas read precisa saber o nome da variável para ler, não seu valor.

ou, com um loop while,

#!/bin/bash

read -p 'number please: ' num

i=0
while (( ++i <= num )); do
    printf 'counter is at %d\n' "$i"
done

O (( ... )) em bash é um contexto aritmético. Em tal contexto, você não precisa colocar $ em suas variáveis, e os valores das variáveis serão interpretados como inteiros.

ou, com /bin/sh ,

#!/bin/sh

printf 'number please: ' >&2
read num

i=1
while [ "$i" -le "$num" ]; do
    printf 'counter is at %d\n' "$i"
    i=$(( i + 1 ))
done

O teste -le ("menor que ou igual") precisa atuar em duas expansões de variáveis citadas (neste código). Se eles não fossem citados, como em [ $i -le $num ] , então, se qualquer variável contivesse um caractere de globalização de concha ou um espaço, você poderia obter resultados inesperados ou erros. Além disso, a cotação protege os números caso a variável IFS contenha dígitos.

Perguntas relacionadas:

por 15.05.2018 / 19:19
3

Para resolver a questão específica:

Do I need to convert the string to an int some how?

A resposta é não. As variáveis do shell são todas strings, mas dependendo do contexto em que são usadas, elas podem ser tratadas como inteiros ou strings. No caso do operador -le do comando [ (também conhecido como comando test ), as variáveis serão tratadas como números inteiros.

# integer comparison
$ var=25; test "$var" -le "$HOME"
bash: test: /home/username: integer expression expected
$ test "$var" -le 30 && echo Lower
Lower
# string comparison
$ test $var = 24 && echo 'same string' || echo 'different string'
different string
$ test $var = 25 && echo 'same string' || echo 'different string'
same string

Seu script precisa inicializar a variável counter , descartar $ de numOfBytes em read e remover $ de let .

#!/bin/bash

read -p "How many bytes would you like you replace :> " numOfBytes
echo "$numOfBytes bytes to replace"
counter=0
while [ "$counter" -le "$numOfBytes" ]
do
    echo "testing counter value = $counter"
    let counter++
done

Isso funciona assim:

$ ./counter.sh 
How many bytes would you like you replace :> 5
5 bytes to replace
testing counter value = 0
testing counter value = 1
testing counter value = 2
testing counter value = 3
testing counter value = 4
testing counter value = 5

Observe que, devido à palavra-chave let sendo bash / ksh , isso torna o script menos portável. Seria aconselhável fazer uso da expansão aritmética counter=$((counter+1)) , que é parte do Idioma da Shell do POSIX padrão (seção 2.6.4).

Veja também: link

Como Storm Dragon apontou, o fato de que variáveis de shell são tratadas dependendo de seu contexto também implica que o usuário a entrada precisa ser sanitizada. Uma maneira possível é usar numOfBytes em case steatement portátil como em esta resposta , que cuida de determinar se a entrada é na verdade um dígito.

    
por 15.05.2018 / 19:43
3

O Bash realmente não tem tipos atribuíveis. A variável é o tipo de sua declaração. Então, se você declarar uma variável como abc , é uma string. Se você declarar como 138 , é um int. Bash realmente não manipula decimais, então se você declarar variável como 138.0 , ele trata como uma string.

Portanto, você precisa ter cuidado com a entrada do usuário, porque não é possível executar o loop de 0 para abc . Aqui está um exemplo que deve fornecer uma verificação de erros e incrementar os bytes em um loop.

#!/bin/bash

# Handle non-numeric input
read -p "How many bytes would you like you replace :> " numOfBytes
while [[ ! "$numOfBytes" =~ ^[0-9]+$ ]]; do
    echo
    echo "Please enter whole numbers only:"
    read -p "How many bytes would you like you replace :> " numOfBytes
done

echo "$numOfBytes bytes to replace $numOfBytes"
for i  in $(seq $numOfBytes) ; do
    echo "i has been incremented to $i."
done
exit 0
    
por 15.05.2018 / 20:36