2010-07-17 21 views
6

Me estoy haciendo una serie de números en una tubería, y le gustaría realizar algunas operaciones antes de pasarlos a la siguiente sección, pero estoy un poco perdido sobre cómo Lo haría sin romper la tubería.BASH: cómo realizar operaciones aritméticas con números en un tubo de

por ejemplo

> echo "1 2 3 4 5" | some command | cat 
1 4 9 16 25 
> 

¿Tiene usted alguna idea de cómo hacer algo como esto? La operación real que quiero realizar es simplemente agregar una a cada número.

Respuesta

7
echo 1 2 3 4 5|{ 
    read line; 
    for i in $line; 
    do 
    echo -n "$((i * i)) "; 
    done; 
    echo 
} 

El {} crea una agrupación. En su lugar, podría crear un script para eso.

+0

Gracias Mateo! Exactamente lo que estaba buscando. En retrospectiva, debería haber sido capaz de resolver esto por mi cuenta, aunque :-p – brice

+0

No es necesario un subnivel en absoluto. Reemplace su subshell inútil, fea e ineficiente por una agrupación '{...}'. –

+0

Para aquellos confundidos por el comentario de @gniourf_gniourf, se aplicó a la respuesta no editada que ahora se ha editado para incluir la agrupación '{}'. –

0

Si prefiere Python:

#!/bin/python 
num = input() 
while num: 
    print(int(num) + 1) # Whatever manipulation you want 
    try: 
     num = input() 
    except EOFError: 
     break 
3

O ..

echo "1 2 3 4 5" | xargs -n 1 | while read number 
do 
    echo $((number * number)) 
done 
+0

Gracias lasseoe. Para ponerlo en el medio de la tubería, tendría que ponerlo en una subcapa también. Sin embargo, el tuyo no suelta los números, ¡que es mejor! – brice

+0

En realidad, todos los comandos de shell en un conducto se ejecutan automáticamente en una subshell; la única razón para poner esto en '()' sería agruparlo con un 'eco' final como lo hizo Matthew Flaschen, e incluso allí podrías usar' {} '(que agrupar sin forzar una subshell). –

1

O puede canalizar a la expresión de BC:

echo "1 2 3 4 5" | (
    read line; 
    for i in $line; 
    do 
    echo $i^2 | bc; 
    done; 
    echo 
) 
4

me gustaría escribir:

echo "1 2 3 4 5" | { 
    for N in $(cat); do 
    echo $((N ** 2)) 
    done | xargs 
} 

podemos pensar en él como un "mapa" (programación funcional). Hay muchas formas de escribir una función de "mapa" en bash (utilizando la entrada estándar, argumentos de funciones, ...), por ejemplo:

map_stdin() { 
    local FUNCTION=$1 
    while read LINE; do 
    $FUNCTION $LINE 
    done 
} 

square() { echo "$(($1 * $1))"; } 

$ echo "1 2 3 4 5" | xargs -n1 | map_stdin square | xargs 
1 4 9 16 25 
1
echo 1 2 3 4 5 | xargs -n 1 bash -c 'echo $(($1*$1))' args 
1
echo 1 2 3 4 5 | xargs -n 1 expr -1 + 
+0

Esto simplemente emite los 5 números para mí. – Tim

-1

Yoi puede gustar algo como esto:

echo "1 2 3 4 5" | perl -ne 'print $_ ** 2, " " for split//, $_' 

ni aun como este:

echo "1 2 3 4 5" | perl -ne 'print join " ", map {$_ ** 2} split//, $_' 
1

Utilizando awk es otra solución bastante compacto

echo "1 2 3 4 5" | xargs -n1 | awk '{print $1**2}' | xargs 
0

xargs, xargs, xargs

echo 1 2 3 4 5 | xargs -n1 echo | xargs -I NUMBER expr NUMBER \* NUMBER | xargs 

O ir en paralelo:

squareit() { expr $1 \* $1; } 
export -f squareit 
echo 1 2 3 4 5 | xargs -n1 | parallel --gnu squareit | xargs 

cual sería manera más simple si usted pasó su tubería como un conjunto estándar de args:

parallel --gnu "expr {} \* {}" ::: $(echo 1 2 3 4 5) | xargs 

O incluso:

parallel --gnu "expr {} \* {}" ::: 1 2 3 4 5 | xargs 

Realmente vale la pena echar un vistazo a los ejemplos en el documento: https://www.gnu.org/software/parallel/man.html

Cuestiones relacionadas