2015-04-17 42 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

相關問題