简体   繁体   English

Ubuntu bash脚本重用输入变量

[英]Ubuntu bash script reuse input variable

I am trying to implement a bash script that reads input from a piped command. 我正在尝试实现从管道命令读取输入的bash脚本。 I want to process each line on the input and perform some processing on each line. 我想处理输入中的每一行并在每一行上执行一些处理。 Additionally, I want to reuse the input passed to the script. 另外,我想重用传递给脚本的输入。 However, I have noticed that I am unable to reuse the input. 但是,我注意到我无法重复使用输入。 Below is my script: 下面是我的脚本:

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

This script is to be executed like this: 该脚本将像这样执行:

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

Sample data is: 样本数据为:

1 STATUS
2 AUTHORISED
11 SENT

If the script is modified to something like this: 如果将脚本修改为如下所示:

#!/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

This script only ouputs the total and the while loop is not executed. 该脚本仅输出总数,而while循环不执行。

Multiple piped commands are required for this task, as this script will be used by many things so that it is kept generic and reusable. 此任务需要多个管道命令,因为此脚本将被许多事物使用,以便保持通用性和可重用性。 How can this be achived without storing the contents to a file? 在不将内容存储到文件的情况下如何实现?

Sample Input: 输入样例:

1 STATUS
2 AUTHORISED
11 SENT

Total would be 14. So each item ie 1/14*100,2/14*100 and 11/14*100. 总计为14。因此每个项目,即1/14 * 100、2 / 14 * 100和11/14 * 100。

This is easy: 这很容易:

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

For the grep operation part: 对于grep操作部分:

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

If the input is not in a file, we can cache it in awk itself. 如果输入不在文件中,我们可以将其缓存在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

If you want to perform arithmetic based on the total, you need to know that total before performing your arithmetic. 如果要基于总数执行算术,则需要在执行算术之前知道该总数。 So you need two loops -- one to read the data and add up the total, and the other to process that data based on the total. 因此,您需要两个循环-一个循环读取数据并累加总数,另一个循环基于总数处理该数据。

#!/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

Remember that bash only supports integer math, so it's important to use 100 * $val1 / $val2 rather than $val1 / $val2 * 100 . 请记住,bash仅支持整数数学运算,因此使用100 * $val1 / $val2而不是$val1 / $val2 * 100 If you want greater precision, consider using external tools like bc or dc instead of doing your math in bash alone. 如果要提高精度,请考虑使用bcdc等外部工具,而不是仅使用bash进行数学计算。

My results with the script above on the sample data in your question: 我在上面的脚本中对问题中的示例数据的结果:

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

Your script won't work because your $1 arg is empty. 您的脚本将无法运行,因为$ 1参数为空。

Use xargs to get the argument instead of using it as stdin. 使用xargs获取参数,而不是将其用作stdin。 Also since the output could be multi line you can use -0 on xargs to use the null delimiter. 同样,由于输出可能是多行,因此可以在xargs上使用-0来使用空定界符。

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

Then you need to actually calculate the total, I did that here using awk because I was being lazy, but there is probably an easier way. 然后,您需要实际计算总数,我在这里使用awk这样做是因为我很懒,但是可能有一种更简单的方法。

You can then read input line by line using read. 然后,您可以使用read逐行读取输入。

I edited the script to work for me in a test environment, see below: 我编辑了脚本以在测试环境中为我工作,请参见下文:

#!/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  

You are better off using a temporary file. 您最好使用临时文件。 But it's easy enough to store the data in memory. 但是将数据存储在内存中很容易。

(This script assumes you are totaling column one, and that column one in each line is a count of data points matching the status in column 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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM