Você não deve usar expr
neste caso, tente isto:
table_value=$(( 1 / (1+$levenshtein_return) ))
Estou comparando duas strings usando o algoritmo levenshtein distance
. Eu tenho a implementação PHP do algoritmo de aqui . Eu estou chamando esta implementação php do meu script de shell como abaixo.
levenshtein_return=$(php levensh.php "String1" "String2")
A variável levenshtein_return
contém o valor como 1 agora, pois há uma diferença de caractere único.
Agora, antes de inserir o valor como tal nas tabelas do banco de dados, preciso executar algumas operações aritméticas usando essa variável. Eu estou tentando implementar como,
table_value=$( expr( 1/ ( 1 + $levenshtein_return ) ) )
No entanto, se eu usar a sintaxe acima, estou recebendo um erro como
line 52: syntax error near unexpected token '1'
Como posso alterar a instrução expr para que eu possa obter o valor real da variável table_value
?
Existem alguns problemas aí.
Em:
table_value=$( expr( 1/ ( 1 + $levenshtein_return ) ) )
Os caracteres (
e )
são especiais para o shell, portanto, deve ser escapado. E é o comando expr
que você deseja executar, não o comando expr(
. Além disso, você deve passar operadores e operandos como argumentos separados para expr
.
table_value=$(expr '(' 1 / "(" 1 + "$levenshtein_return" \) ')' )
(acima, mostrando as diferentes maneiras de citar os caracteres (
e )
).
Agora, como @Gnouc mostrou , expr
não é mais necessário para avaliação aritmética como todos os POSIXs modernos shells têm um operador interno $((...))
para isso.
Agora, exceto com zsh
e ksh93
, nem expr
nem $((...))
fazem aritmética de ponto flutuante. Então, em ambos:
table_value=$(expr 1 / "(" 1 + "$levenshtein_return" ")" )
e
table_value=$((1 / (1 + $levenshtein_return)))
O valor será inteiro, então tipicamente 0 ou 1.
Se você quisesse ter 1 se as strings forem iguais e 0 se forem diferentes (mas, você não precisa calcular a distância se tudo o que você quer fazer é verificar se as duas strings são as mesmas) , então você teria escrito:
table_value=$((!$levenshtein_return))
Em ksh93
ou zsh
, se você quisesse um valor de ponto flutuante, escreveria:
table_value=$((1. / (1 + $levenshtein_return)))
Em outros shells, e POSIXly, se você precisar de aritmética de ponto flutuante, normalmente chama um comando que pode fazer isso como awk
, bc
ou ... php
.
Aqui, como você já está invocando php
, é melhor fazer o cálculo final também. Se estiver usando awk
, observe que awk
também pode fazer o cálculo de distância do Levenshtein com facilidade:
table_value=$(awk '
function min(x, y) {
return x < y ? x : y
}
function lev(s,t) {
m = length(s)
n = length(t)
for(i=0;i<=m;i++) d[i,0] = i
for(j=0;j<=n;j++) d[0,j] = j
for(i=1;i<=m;i++) {
for(j=1;j<=n;j++) {
c = substr(s,i,1) != substr(t,j,1)
d[i,j] = min(d[i-1,j]+1,min(d[i,j-1]+1,d[i-1,j-1]+c))
}
}
return d[m,n]
}
BEGIN {print 1 / (1 +lev(ARGV[1], ARGV[2])); exit}' String1 String2
)
Embora não seja documentado e não seja garantido pelo POSIX, parece que, como o POSIX requer shells para manipular constantes C e muitos dos mesmos operadores C, eles parecem originar todo o resto dos operadores matemáticos integrais C simples, bem , incluindo testes e atribuições ternárias:
% a=abc
% b=abcd
% t=1 ; f=0
% echo $((r=${#a}>${#b}?t:f)) ; echo $r
> 0
> 0
% echo $((r=${#a}<${#b}?t:f)) ; echo $r
> 1
> 1
Acabei de testar o exemplo básico acima em zsh, bash, sh do bash e dash. Todos se comportaram corretamente e identicamente.
Tags scripting shell-script