Sequência de argumentos para número inteiro no bash

74

Tentando descobrir como converter um argumento em um número inteiro para executar aritmética e, em seguida, imprimi-lo, diga addOne.sh:

echo $1 + 1
>>sh addOne.sh 1
prints 1 + 1
user135986
fonte
Tento formatar sua pergunta, mas ela ainda não está clara. printf "1 + %s\n" $1 won't do ?
Archemar 27/09/2015

Respostas:

89

No bash, não se "converte um argumento em um número inteiro para executar aritmética". No bash, as variáveis ​​são tratadas como número inteiro ou string, dependendo do contexto.

Para executar aritmética, você deve chamar o operador de expansão aritmética $((...)). Por exemplo:

$ a=2
$ echo "$a + 1"
2 + 1
$ echo "$(($a + 1))"
3

ou geralmente preferido:

$ echo "$((a + 1))"
3

Você deve estar ciente de que o bash (ao contrário de ksh93, zsh ou yash) executa apenas aritmética inteira . Se você possui números de ponto flutuante (números com decimais), existem outras ferramentas para ajudá-lo. Por exemplo, use bc:

$ b=3.14
$ echo "$(($b + 1))"
bash: 3.14 + 1: syntax error: invalid arithmetic operator (error token is ".14 + 1")
$ echo "$b + 1" | bc -l
4.14

Ou você pode usar um shell com suporte aritmético de ponto flutuante em vez de bash:

zsh> echo $((3.14 + 1))
4.14
John1024
fonte
Usar $ (()) ou (()) não é seguro se você não souber quais são as strings (como a entrada do usuário). Considere o seguinte: foo = foo ((foo + = 0)) Isso travará o script ao tentar avaliar recursivamente foo. O mesmo acontece com: foo = foo foo = $ ((foo + 0))
art
12

Por outro lado, você pode usar expr

Ex:

$ version="0002"
$ expr $version + 0
2
$ expr $version + 1
3
Nam
fonte
10

Em bash, você pode executar a conversão de qualquer coisa para inteiro usando printf -v :

printf -v int '%d\n' "$1" 2>/dev/null

O número flutuante será convertido em número inteiro, enquanto qualquer coisa que não seja parecida com um número será convertida em 0. A exponenciação será truncada para o número anterior e

Exemplo:

$ printf -v int '%d\n' 123.123 2>/dev/null
$ printf '%d\n' "$int"
123
$ printf -v int '%d\n' abc 2>/dev/null
$ printf '%d\n' "$int"
0
$ printf -v int '%d\n' 1e10 2>/dev/null
$ printf '%d\n' "$int"
1
cuonglm
fonte
2
Em outros shells sem printf -visso, pode ser alcançado com a substituição de comandos:int="$(printf '%d' 123.123 2>/dev/null)"
Adrian Günter
2
Isso não funciona no bash.
Michael Martinez
@MichaelMartinez tem certeza? Qual a versão que bashvocê usou?
cuonglm 23/01
GNU bash, versão 4.2.46 (1) -release (x86_64-redhat-linux-gnu)
Michael Martinez
5

Uma situação semelhante surgiu recentemente ao desenvolver scripts bash para execução nos ambientes Linux e OSX. O resultado de um comando no OSX retornou uma sequência contendo o código do resultado; ou seja, " 0". Obviamente, isso falhou ao testar corretamente no seguinte caso:

if [[ $targetCnt != 0 ]]; then...

A solução foi forçar (ou seja, 'converter') o resultado para um número inteiro, semelhante ao que @ John1024 respondeu acima, para que funcione conforme o esperado:

targetCnt=$(($targetCnt + 0))
if [[ $targetCnt != 0 ]]; then...
JESii
fonte
3
==etc em [[(também [conhecido como test) faça comparação de strings. Existem diferentes operadores para comparação aritmética, por exemplo [[ $targetcnt -ne 0 ]]; consulte a página de manual (ou informações) em Expressões condicionais. Para aparar espaços especificamente, você pode usar [a expansão de variáveis ​​não citadas [ $targetcnt == 0 ]para obter a divisão de palavras padrão (NÃO feita em [[), mas em geral essa abordagem leva você ao perigo.
Dave_thompson_085
-2

Se preocupam com códigos de cores, mesmo em trace ( -x) eles não aparecerão, o que o denunciaria é que a string que deveria ser um número está entre aspas, não importa como você a imprima.

desenterrar
fonte
11
Votado, pois acho a sua resposta um pouco clara. Talvez você possa adicionar a que o script deve ser corrigido?
Time4Tea
essa foi a principal resposta na busca por bash + inteiro + string, então eu adicionei uma informação relacionada a ela que não foi incluída nas respostas, ou seja, quando as strings estão envolvidas em códigos de cores, pode não estar claro por que operações como $((var+var))falhas embora se você echoou os printfdois vars são iguais. Não conheço a correção, pois só consegui corrigi-la desativando os códigos de cores na fonte da saída. Para identificá-lo nos logs de rastreamento, você verá a variável ofensiva atribuída como var='0'deveria ser simplesmentevar=0
desatou
O que você pode fazer é se certificar a saída não tem códigos de cores com sedse você não pode desativá-lo
untore