2010-07-17 3 views
6

Я получаю поток чисел в трубе и хотел бы выполнить некоторые операции, прежде чем передавать их в следующий раздел, но я немного потерял о том, как Я бы обошел его, не нарушая трубы.BASH: как выполнить арифметику по номерам в трубе

, например

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

Вы бы иметь какие-либо идеи о том, как сделать что-то вроде этой работы? Фактическая операция, которую я хочу выполнить, - это просто добавить один к каждому номеру.

ответ

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

{} создает группировку. Вместо этого вы можете создать для этого сценарий.

+0

Спасибо Мэтью! Именно то, что я искал. Оглядываясь назад, я должен был это понять самостоятельно, хотя: -p – brice

+0

Вам совсем не нужна подоболочка. Замените свою бесполезную, уродливую и неэффективную подоболочку на группировку '{...}'. –

+0

Для тех, кто смущен комментарием @gniourf_gniourf, он применил к неотредактированному ответу, который теперь редактировался, чтобы включить '{}' группировку. –

0

Если вы предпочитаете Python:

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

Или ..

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

Спасибо lasseoe. Чтобы положить его в середину трубы, мне нужно было бы поставить его в подоболочку тоже. Однако ваш не уменьшает числа, что лучше! – brice

+0

На самом деле, любые команды оболочки в трубе автоматически запускаются в подоболочке; единственная причина поместить это в '()' состояла бы в том, чтобы сгруппировать его с окончательным «эхом», как это сделал Мэтью Флашен, и даже там вы могли бы просто использовать '{}' (которые группируются без принуждения подоболочки). –

1

Или вы можете трубы для выражения Ьс:

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

Я бы написать:

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

Мы можем думать об этом как о «карте» (функциональном программировании). Есть много способов написания функции «карта» в Баш (с использованием стандартного ввода, функция арг, ...), например:

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

Это просто выводит 5 чисел для меня. – Tim

-1

YOI могли бы что-то вроде этого:

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

или даже так:

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

Использование AWK является другой довольно компактное решение

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 

Или идут параллельно:

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

Какой бы способ проще, если вы сдадите трубу в качестве стандартного набора args:

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

Или даже:

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

Действительно стоит взглянуть на примеры в док: https://www.gnu.org/software/parallel/man.html

Смежные вопросы