2009-12-04 36 views
6

Soy bastante nuevo en el scripting bash y generalmente evito todos los costos, pero necesito escribir un script bash para ejecutar algunas cosas simples en un clúster remoto. Estoy teniendo problemas con un bucle for que hace lo siguiente:Sentencias matemáticas sencillas en bash en un bucle for

for i in {1..20} 
do 
    for j in {1..20} 
    do 
     echo (i*i + j*j) **.5 <--- Pseudo code! 
    done 
done 

¿Puede ayudarme con esta simple matemática? Lancé $ en todas partes y no puedo escribirlo correctamente. Si pudieras ayudarme a entender cómo se nombran/asignan las variables en bash para los bucles y las limitaciones de la interpretación matemática bash (¿cómo se hace la raíz cuadrada?), Estaría muy agradecido. ¡Gracias!

Respuesta

8

Aquí hay una solución decente:

for i in {1..20} 
do 
    for j in {1..20} 
    do 
     echo "scale = 3; sqrt($i*$i + $j*$j)" | bc 
    done 
done 

de salida será:

1.414 
2.236 
3.162 
2.236 
[...etc...] 
0

Use doble paren para evaluar una variable.

variableA = $ ((* variableB variableC))

Sólo para enteros sin embargo.

0

Normalmente usaría $ ((1 * 3)), pero su caso no funcionará ya que bash no es compatible con los números de coma flotante. Tendrá que usar una herramienta externa como awk, bc o dc: http://mywiki.wooledge.org/BashFAQ/022

2

Las operaciones de shell se pueden realizar de varias maneras.

echo $((i*i + j*j)) 
echo $[ i*i + j*j ] 
expr "$i" '*' "$i" '+' "$j" '*' "$j" 

Sin embargo, esto solo puede manejar la aritmética de enteros. En su lugar, puede utilizar bc:

echo "scale = 5; sqrt($i*$i + $j*$j)" | bc 

Cambio scale al número de decimales deseados.

+0

Me estoy poniendo muy numerosos (standard_in) 1: parse error – physicsmichael

+0

Probablemente se esté perdiendo la ' ..' entre tu 1 y 20 en tu {1..20} rango – dustmachine

+0

Extraño, debería funcionar en cualquier POSIX 'bc'. ¿Qué pasa si usas 'dc'? es decir 'dc -e" 5 k $ i $ i * $ j $ j * + v p "' – ephemient

9

expansión aritmética necesita $((...)) notación, así que algo como:

echo $((i*i + j*j)) 

Sin embargo, fiesta sólo se utiliza enteros por lo que puede que tenga que utilizar una herramienta externa, tales como DC.

E.g.

dc -e "18k $i $i * $j $j * + v p" 
0

El código

echo $[(($i * $i) + ($j * $j)) ** $X] 

funcionará si $X es un número entero. Estás intentando tomar la raíz cuadrada, y no estoy seguro de si la aritmética incorporada de bash hará eso. Probablemente sea mejor utilizar una herramienta de cálculo más poderosa (como bc, et al.) Para esto.

2
#!/bin/bash 
for i in {1..20}; do 
    for j in {1..20}; do 
     echo 5k$i $i\* $j $j\*+vp | dc 
    done 
done 
+0

Mi variante: 'printf"% s% s 10kd * rd * + vp "" $ i "" $ j "| dc' –

0

Bash no ofrece funciones matemáticas. Sin embargo, es casi seguro que tenga instalado el shell korn.Esto debería funcionar:

#!/bin/ksh 

for i in {1..20} 
do 
    for j in {1..20} 
    do 
     x=$((sqrt(i*i + j*j))) 
     echo "sqrt($i^2 + $j^2) = $x" 
    done 
done 

El comienzo de la salida es

sqrt(1^2 + 1^2) = 1.41421356237309505 
sqrt(1^2 + 2^2) = 2.2360679774997897 
sqrt(1^2 + 3^2) = 3.16227766016837933 
sqrt(1^2 + 4^2) = 4.12310562561766055 
sqrt(1^2 + 5^2) = 5.09901951359278483 
sqrt(1^2 + 6^2) = 6.08276253029821969 
sqrt(1^2 + 7^2) = 7.07106781186547524 
sqrt(1^2 + 8^2) = 8.06225774829854965 
sqrt(1^2 + 9^2) = 9.05538513813741663 
sqrt(1^2 + 10^2) = 10.0498756211208903 
+0

"casi con certeza"? Ciertamente no estándar en cualquier distribución de Linux que he visto. Quizás te refieres a * BSD? – ephemient

+0

Mac OSX 10.6 lo tiene. – physicsmichael

+0

OSX tiene el estilo de BSD. –

-1

Otra forma de expresiones matemáticas de números enteros en Bash pone los dobles paréntesis, en el exterior de toda la expresión para las operaciones de asignación:

((var = i ** 2)) 
((i++)) 
((position += delta)) 

Como puede ver, los signos de dólar no son necesarios aquí (ni dentro de $(())). Además, se permiten espacios alrededor del signo igual.

Además, esta forma se puede utilizar en los condicionales:

sixpacks=8    # note spaces not allowed here 
((beerprice = 8)) # but you can use spaces this way 
budget=50 

# you can do assignments inside a conditional just like C 
until ((((beertotal = sixpacks * beerprice)) <= budget)) 
do 
    ((sixpacks--)) 
done 
echo "Buy ${sixpacks} six-packs at \$${beerprice} each for a total of \$${beertotal}." 

o se puede sustituir todo lo relacionado con esto, por supuesto:

beerprice=8 
budget=50 

# integer division 
((sixpacks = budget/beerprice)) 
((beertotal = sixpacks * beerprice)) 
echo "Buy ${sixpacks} six-packs at \$${beerprice} each for a total of \$${beertotal}." 

Bash también tiene una declaración let:

let a=2**16 
let 'a>>=1' # bitwise shift - some operations need to be quoted or escaped 
((a>>=1)) # but not inside (()) 
1

¿su clúster remoto solo tiene bash? si no, tratar de ver si ha awk

awk 'BEGIN{ 
    for(i=1;i<=20;i++){ 
    for(j=1;j<=20;j++){ 
     print (i*i + j*j) ** 0.5 
    } 
    } 
}' 
0

con zsh, esto funcionará

for i in {1..20};do 
    for j in {1..20};do 
    echo $((($i*$i + $j*$j)**.5)) 
    done 
done