2015-04-17 196 views
0

我有一个bash脚本的时候这样调用它的工作原理:./stats.sh -rows test_file如何通过一个文件作为标准输入的shell脚本

程序基本上计算行平均值和中位数&列平均值和中位数。现在我要将文件作为标准输入传递给程序。但是当我运行这个代码时,它打印"you have 2 provide 2 arguments"。我必须做出什么样的改变,以便代码将stdin作为文件。我的意思是说如果我想运行脚本,我可以通过这种方式运行它./stats.sh -rows < test_file。我想获得这个功能!

输入文件是:

93 93 93 93 93 93 93 93 100 
73 84 95 83 72 86 80 97 100 
85 0 82 75 88 79 80 81 100 
85 0 87 73 88 79 80 71 100 
80 81 83 63 100 85 63 68 100 
53 57 61 53 70 61 73 50 100 
55 54 41 63 63 45 33 41 100 
53 55 43 44 63 75 35 21 100 
100 100 100 100 100 100 100 100 100 

这是我制作的代码是这样(列由制表符分隔):

#! /bin/bash 
clear 
#the arguments below will check for your command line args whether you have provided corrctly or not 
flag=0 
if [ "$#" -eq 0 ]; then 
    echo "Please provide arguments" 
elif [ "$#" -lt 2 ]; then 
    echo "You have to provide 2 arguments" >&2 
    exit 1 
elif [ "$#" -gt 2 ]; then 
    echo "${#}" 
    FILE= "${4}" 
    if [ -f "${FILE}" ]; then 
    flag=1 
    else 
     echo "You have provided more number of arguments" >&2 
    fi 
    exit 1 
else 
    echo "You have entered correct number of arguments" 
fi 
# the below code is the case code which checks whether you have -r/-rows or -c/-cols 
option="${1}" 
l1=0 
sorted=() 
case ${option} in 
    -rows| -r| -r*) 
     if [ $flag -eq 1 ]; then 
     FILE="${4}" 
     else 
     FILE="${2}" 
     fi 
     clear 
     echo "Average Median" 
     lines=$(wc -l < "$FILE") 
     while read -r line 
     do 
     len=0 
     tot=0 
     name=$line 
     #array=(`echo $name | cut -d " " --output-delimiter=" " -f 1-`) 
     IFS=' ' read -a array <<< "$name" #if any error comes that might be with this line just check the spaces in the speech marks they should be 4 spaces as it is checking for tabs 
     for element in "${array[@]}" 
     do 
      tot=$(expr $tot + $element) 
      #let tot+=$element #you can use this as well to get the totals 
      let len+=1 
     done 
     avg=($(printf "%.0f" $(echo "scale=2;$tot/$len" | bc))) 
     readarray -t sorted < <(for a in "${array[@]}"; do echo "$a"; done | sort) 
     no=`expr $len % 2` 
     if [ $no -eq 0 ]; then 
     mid=`expr $len/2` 
     echo "$avg ${sorted[$mid]}" 
     else 
     if [ $lines -lt 2 ]; then 
     mid=`expr $len/2` 
      echo "$avg ${sorted[$mid]}" 
     else 
     l1=`expr $len/2` 
     mid=`expr $l1 + 1` 
     echo "$avg ${sorted[$mid]}" 
     fi 

     fi 
     unset "array[@]" 
     unset "sorted[@]" 
     done < "$FILE" 
     ;; 

    -cols| -c| -c*) 
     if [ $flag -eq 1 ]; then 
     FILE="${4}" 
     else 
     FILE="${2}" 
     fi 
     #echo "cols" 
     #echo "File name is $FILE" 
     cols=$(head -1 "$FILE" | tr "\t" '\n' | wc -l) 
     lines=$(wc -l < "$FILE") 
     IFS=$'\t\n' read -d '' -r -a lins < "$FILE" 
     while read line;do 
     x=1 
     read -a array <<< "$line" ##Split the line by spaces 
     for element in "${!array[@]}" 
     do 
     row[${element}]=$((${row[${element}]}+${array[$element]})) ##For each column increment array variable by number in the column. 
     ((x++)) 
     done 
     done < "$FILE" 
     echo "Averages: " 
     for element in ${row[@]} 
     do 
     mean= printf "%.0f" $(echo "scale=2;$element/$lines" | bc) ##bc prints floating point numbers and then we round of using scale and .0f 
     echo -n "$mean " 
     done 
     printf "\n" 
     echo "Medians: " 
     for ((i=0;i<$cols;i++)) 
     do 
     carr=() 
     for ((j=i;j<$lines * $cols;j=j+$cols)) 
     do 
      carr+=(${lins[$j]}) 
     done 
    IFS=$' \n' csort=($(sort <<<"${carr[*]}")) 
    no=`expr $lines % 2` 
    if [ $no -eq 0 ]; then 
      mid=`expr $lines/2` 
      echo -n "${csort[$mid]} " 
    else 
      if [ $lines -lt 2 ]; then 
        mid=`expr $lines/2` 
       echo -n "${csort[$mid]} " 
      else 
       l1=`expr $lines/2` 
       mid=`expr $l1 + 1` 
       echo -n "${csort[$mid]} " 
      fi 
    fi 
     done <<<"$lins" 
     printf "\n" 

     ;; 
    *) 
     echo "`basename ${0}`:usage: [-r|-rows rows] | [-c|-cols columns]" 
     exit 1 # Command to come out of the program with status 1 
     ;; 
esac 
trap "echo ;exit" 1 2 
+0

我不是bash/shell的主人,但你不能只使用'cat file.txt | stats.sh'? –

+0

@ Al.G。这显然是理想的,但脚本旨在专门防止这种情况。 – tripleee

回答

0

使用read a洞察你的bash脚本读取/处理标准输入的内容。

实施例:

skript.sh:

read a 
echo "content of std in" 
echo a 

在这种情况下cat test_file.txt | stats.sh将工作。

0

您也可以重定向一个文件到您的脚本中的标准输入:

# redirect FILE to stdin 
exec 0<$FILE 
# read from FILE 
read VAR 
0

在许多现代建筑,如果脚本确实需要你通过一个文件名参数,你可以通过/dev/stdin有标准输入可用作为文件名称的实体。许多脚本也接受-作为特殊文件名,意思是“不要打开文件;改为读取标准输入”。像./stats.sh -rows - <file这样的东西实际上也可能工作。 (当然,这是一个愚蠢的例子,因为./stats.sh -rows file是同等物;但它很重要的东西,像stuff | ./stats.sh -rows -。)

然而,剧本从众多的设计缺陷受到影响,也有至少一个语法错误(你不能有空间在FILE= "${4}"。第四个参数将被简单地评估为一个命令,这可能会带来安全隐患,这取决于你如何运行这个脚本)。我会认真考虑用一两个简单的Perl或Awk脚本完全替换它。这个shell对于你负责的算术来说并不是很理想。

+0

感谢您的回答和建议。我实际上使用python这个,但我正在学习bash,所以我只是写在bash中 – ayaan

相关问题