我正在尝试实现一个从管道命令读取输入的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.
答案 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
非常重要。如果您想要更高的精确度,请考虑使用bc
或dc
等外部工具,而不是单独使用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