2010-07-17 12 views
6

Ich bekomme eine Reihe von Zahlen in einer Pipe und möchte einige Operationen ausführen, bevor ich sie an die nächste Sektion weitergebe, aber ich bin ein wenig darüber verloren Ich würde es machen, ohne die Pfeife zu zerbrechen.BASH: Wie arithmetische Operationen an Zahlen in einer Pipe durchgeführt werden

zum Beispiel

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

Würden Sie irgendwelche Ideen, wie man so etwas wie diese Arbeit zu machen? Die eigentliche Operation, die ich ausführen möchte, besteht darin, zu jeder Nummer einen zu addieren.

Antwort

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

Das {} erstellt eine Gruppierung. Sie könnten stattdessen ein Skript dafür erstellen.

+0

Dank Matthew! Genau das, was ich gesucht habe. Rückblickend hätte ich das selbst herausfinden können: -p – brice

+0

Sie brauchen überhaupt keine Subshell. Ersetzen Sie Ihre nutzlose, hässliche und ineffiziente Subshell durch eine Gruppierung '{...}'. –

+0

Für diejenigen, die durch den Kommentar von @gniourf_gniourf verwirrt waren, galt dies für die unbearbeitete Antwort, die jetzt editiert wurde, um '{}' Gruppierung einzubeziehen. –

0

Wenn Sie es vorziehen Python:

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

Oder ..

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

Danke lassoee. Um es in die Mitte der Pfeife zu setzen, müsste ich es auch in eine Unterschale legen. Aber deine Zahlen fallen nicht, das ist besser! – brice

+0

Tatsächlich werden alle Shell-Befehle in einer Pipe automatisch in einer Subshell ausgeführt. der einzige Grund, dies in '()' zu setzen, wäre, es mit einem abschließenden 'Echo' zu gruppieren, wie es Matthew Flaschen tat, und selbst dort könnte man '{}' genauso gut verwenden (was Gruppierung ohne Erzwingen einer Subshell). –

1

Oder Sie können Rohr zum Ausdruck zu bc:

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

Ich würde schreiben:

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

Wir können es als eine "Karte" (funktionale Programmierung) vorstellen. Es gibt eine Menge Möglichkeiten für das Schreiben einer "map" Funktion in bash (mit stdin, Funktion args, ...), zum Beispiel:

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

Dies gibt nur die 5 Zahlen für mich aus. – Tim

-1

Yoi könnten wie folgt erhalten:

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

oder auch wie folgt aus:

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

awk verwenden ist eine ganz andere kompakte Lösung

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 

Oder gehen parallel:

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

Welche Art und Weise einfacher wäre, wenn Sie Ihre Pfeife als Standardsatz bestanden aus args:

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

Oder auch:

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

wirklich lohnt sich, einen Blick auf die Beispiele in der doc unter: https://www.gnu.org/software/parallel/man.html

Verwandte Themen