[英]how to pass a file as stdin in a shell script
I have a bash script which works when called like this: ./stats.sh -rows test_file
我有一个bash脚本,可以按以下方式工作:
./stats.sh -rows test_file
The program basically calculates row averages and medians & column averages and medians. 该程序基本上计算行平均数和中位数,以及列平均数和中位数。 Now to the program I want to pass file as standard input.
现在到程序中,我想将文件作为标准输入传递。 but when I am running this code it prints
"you have 2 provide 2 arguments"
. 但是当我运行此代码时,它会显示
"you have 2 provide 2 arguments"
。 what changes should I have to make so that the code takes stdin as a file. 我应该进行哪些更改,以便代码将stdin作为文件。 I mean to say If I want to run the script I can run it by this way as well
./stats.sh -rows < test_file
. 我的意思是说,如果我想运行脚本,我也可以通过这种方式运行它
./stats.sh -rows < test_file
。 I want to get this functionality!! 我想获得此功能!
the input file is: ( columns separated by tabs ) 输入文件为:(各列之间用制表符分隔 )
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
the code which I worked on is this: 我工作的代码是这样的:
#! /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
Use the read a
insight your bash script to read/process the content of the stdin. 使用“
read a
见解” bash脚本来读取/处理stdin的内容。
Example: 例:
skript.sh: skript.sh:
read a
echo "content of std in"
echo a
In this case cat test_file.txt | stats.sh
在这种情况下,
cat test_file.txt | stats.sh
cat test_file.txt | stats.sh
will work. cat test_file.txt | stats.sh
将起作用。
You may also redirect a file to stdin within your script: 您也可以在脚本中将文件重定向到stdin:
# redirect FILE to stdin
exec 0<$FILE
# read from FILE
read VAR
On many modern architectures, if a script absolutely requires you to pass a file name parameter, you can pass /dev/stdin
to have standard input available as a file name-like entity. 在许多现代体系结构上,如果脚本绝对要求您传递文件名参数,则可以传递
/dev/stdin
以使标准输入可用作类似于文件名的实体。 Many scripts also accept -
as a special file name to mean "don't open a file; read standard input instead". 许多脚本还接受
-
作为特殊文件名,其含义是“不要打开文件;而应阅读标准输入”。 Something like ./stats.sh -rows - <file
might actually work, too. 诸如
./stats.sh -rows - <file
也可能实际上起作用。 (Of course, that's a silly example, since ./stats.sh -rows file
is equivalent; but it matters for something like stuff | ./stats.sh -rows -
.) (当然,这是一个愚蠢的示例,因为
./stats.sh -rows file
是等效的;但是对于诸如stuff | ./stats.sh -rows -
类的stuff | ./stats.sh -rows -
来说,它stuff | ./stats.sh -rows -
。)
However, the script suffers from numerous design flaws, and also has at least one syntax error (you cannot have a space in the assignment FILE= "${4}"
. The fourth argument will simply be evaluated as a command. This might even have security implications, depending on how you run this script). 但是,该脚本有许多设计缺陷,并且还至少存在一个语法错误(在赋值
FILE= "${4}"
不能有空格。第四个参数将简单地作为命令求值。甚至可能具有安全性,具体取决于您运行此脚本的方式)。 I would seriously consider replacing it entirely with one or two simple Perl or Awk scripts. 我会认真考虑用一个或两个简单的Perl或Awk脚本完全替换它。 The shell is just not very ideal for the sort of arithmetic you are tasking it with.
对于您要执行的算法来说,shell并不是很理想。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.