Ubuntu bash脚本重用输入变量

时间:2017-04-25 10:24:52

标签: linux bash ubuntu grep pipe

我正在尝试实现一个从管道命令读取输入的bash脚本。我想处理输入上的每一行并在每一行上执行一些处理。另外,我想重用传递给脚本的输入。但是,我注意到我无法重用输入。以下是我的剧本:

#!/bin/bash
while read line
do
    percentage=$(echo $line | awk 'printf $1')
    # perform some processing using the total i.e. percentage/total*100
done

此脚本将按以下方式执行:

cat data.txt | grep "status" | ./myscript.sh

示例数据是:

1 STATUS
2 AUTHORISED
11 SENT

如果将脚本修改为以下内容:

#!/bin/bash
input=$1
total=$(cut -f1 $1)
echo $total
while read $input
do
    percentage=$(echo $line | awk 'printf $1')
     # perform some processing using the total i.e. percentage/total*100
done

此脚本仅输出总数,而不执行while循环。

此任务需要多个管道命令,因为此脚本将被许多内容使用,以便保持通用和可重用。如何在不将内容存储到文件的情况下实现这一目标?

示例输入:

1 STATUS
2 AUTHORISED
11 SENT

总计为14.所以每个项目,即1/14 * 100,2 / 14 * 100和11/14 * 100.

4 个答案:

答案 0 :(得分:0)

这很简单:

awk 'NR==FNR{a+=$1; next;} {print $1*100/a;}' data.txt data.txt

对于grep操作部分:

awk 'NR==FNR{if ($0 ~ pattern) a+=$1; next;} {if ($0 ~ pattern) print $1*100/a;}' pattern=STATUS data.txt data.txt

如果输入不在文件中,我们可以将其缓存在awk本身。

awk '{a+=$1; b[NR]=$1;} END {for(i in b) print b[i]*100/a;}' data.txt

awk '$0 ~ pattern {a+=$1; b[NR]=$1;} END {for(i in b) print b[i]*100/a;}'  pattern=STATUS data.txt

some_command | awk '$0 ~ pattern {a+=$1; b[NR]=$1;} END {for(i in b) print b[i]*100/a;}'  pattern=STATUS

答案 1 :(得分:0)

如果你想根据总数进行算术运算,你需要在执行算术之前知道总数。所以你需要两个循环 - 一个用于读取数据并累计总数,另一个用于根据总数处理数据。

#!/usr/bin/env bash

# Prepare our variables
declare total=0
declare -a data=()
declare -a newdata=()

# Collect the array data and build our total...
while read value text; do
    data+=($value)
    ((total+=$value))
done

# Process the array, populating a new array with the results.
for i in "${!data[@]}"; do
    newdata[$i]=$(( 100 * ${data[$i]} / $total ))
done

# Show our results
declare -p data
declare -p newdata

请记住,bash仅支持整数数学,因此使用100 * $val1 / $val2而不是$val1 / $val2 * 100非常重要。如果您想要更高的精确度,请考虑使用bcdc等外部工具,而不是单独使用bash进行数学运算。

我在上面的脚本中对您问题中的示例数据的结果:

$ testme.sh < testme.txt
declare -a data=([0]="1" [1]="2" [2]="11")
declare -a newdata=([0]="7" [1]="14" [2]="78")

答案 2 :(得分:0)

您的脚本无法正常工作,因为您的$ 1 arg为空。

使用xargs获取参数,而不是将其用作stdin。此外,由于输出可能是多行,您可以在xargs上使用-0来使用空分隔符。

> cat data.txt | grep -i 'status' | xargs -0 ./myscript.sh

然后你需要实际计算总数,我在这里用awk做了,因为我很懒,但可能有一种更简单的方法。

然后,您可以使用read。逐行读取输入。

我编辑了脚本以便在测试环境中为我工作,见下文:

#!/bin/bash                                              
input="$1"                                               
echo "$input"                                            
total=$(echo "$input" | awk '{sum+=$1} END {print sum}') 
echo "$input" | while read line; do                      
      if [ ! -z "$line" ]; then                          
          num=$(echo $line | awk '{print $1}')           
          percentage=$((100 * num / total))              
          echo "$percentage"                             
      fi                                                 
done  

答案 3 :(得分:0)

最好使用临时文件。但将数据存储在内存中非常容易。

(此脚本假设您总计第一列,每行中的第一列是与第2列中的状态匹配的数据点数):

#!/bin/sh

data=$(cat)  # Read all of the input and store it
total=$(echo "$data" | awk '{s+=$1}END{print s}')
echo "$data" | while read count status; do
        printf "%s:\t%2.2f%%\n" \
        "$status" "$(echo "20k$count $total/100*p" | dc)"
done