燕山大学Linux实验shell程序设计
Posted 用编程写诗
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了燕山大学Linux实验shell程序设计相关的知识,希望对你有一定的参考价值。
本文仅是分享代码设计思想和对书上代码解读仅供参考严禁抄袭!!!
主要是编写shell代码部分问题:
注:for i相当于for i in $* (取全部位置参数)下文存在不在赘述
4.对教材例题4.9 (P108)进行编辑,然后执行。
#!/bin/bash
echo $0 $1 $2 $3 $4 $5 $6 $7 $8 $9
shift
echo $0 $1 $2 $3 $4 $5 $6 $7 $8 $9
shift 4
echo $0 $1 $2 $3 $4 $5 $6 $7 $8 $9
这个题目主要是对执行的位置参数进行的一个操作,将位置参数从0到9进行输出同时也有shift命令,移动1位和移动4位的移动后的显示但是0号位置参数是不会发生改变的!
5.对教材例题4.19 (P132)进行编辑,然后执行。
#!/bin/bash
func()
echo "Let's begin now."
echo $a $b $c
echo $1 $2 $3
echo "The end."
a="Working directory"
b="is"
c=`pwd`
func Welcome You Byby
echo "Today is `date`"
这个主要是考察了shell程序设计的函数这个功能,在函数传参数的时候可以是在程序里面的参数可以直接调用例如:a,b,c这三个参数。也可以是在 调用这个函数的时候传入的三个参数如Welcome You Byby在这里面就是作为位置参数传进去的。
6.对习题4.8 (P141)进行编辑,然后执行。
#!/bin/bash
count=$#
cmd=echo
while [ $count -gt 0 ]
do
cmd="$cmd \\$$count"
count=$(($count-1))
done
eval $cmd
注意:第5版Linux教程这本书里面的这个例子是错误的!!无法正常运行需要将while循环里面的count语句进行修改,修改为count=$(($count-1))。
这个题目主要是将参数进行了一个逆序的输出
$#是特殊Shell变量,指的是参数的个数。
cmd="$cmd \\$$count" $cmd为echo,\\$$count表示最末一个参数,整个语句表示输出最末一个参数
count=$(($count-1))表示参数数量减一
eval $cmd表示运行cmd中的命令
7.对习题4.9进行设计,然后调试、执行。编写一个shell脚本,它把第二个位置参数及以后的各参数指定的文件复制到第一个位置参数指定的目录当中。
dir=$1
shift
for i
do
cp $i $dir
done
首先利用位置参数将第一个位置参数的目录传给dir同时移动一位留下剩下的位置参数,再利用一个for循环以及cp命令将文件复制到指定的目录当中。
8.对习题4.11进行设计,然后调试、执行。
打印指定目录下的某些文件,由第一个参数指出文件所在目录,其余参数是要打印的文件名。
dir=$1
cd $dir
shift
for i
do
pr $i
done
这个问题就是也是同样的道理先利用位置参数得到目录然后通过cd命令先转移到所在的目录然后也是shift命令移动一位利用for循环进行一个遍历在遍历的过程中进行pr命令打印。
9.对习题4.13进行设计,然后调试、执行。利用数组的形式存放10个城市的名字,然后利用for循环把他们循环打印出来。
#!/bin/bash
declare -a city
city=(北京 上海 天津 深圳 石家庄 南京 杭州 苏州 拉萨 沈阳)
for i in 0..9
do
echo $city[$i]
done
这个题目考察的就是一个数组的使用。主要就是定义一个数组(在这里我定义数组实际上是多啰嗦了一句,可以直接进行数组赋值因为shell是弱类型的可以直接进行)。对数组进行赋值赋值10个城市然后利用for循环我这里是利用的采用数组下标的方式来访问数组元素。最终可以得到输出。
10.对习题4.14进行设计,然后调试、执行。编写一个shell脚本求出斐波那契数列的前10项的总和
#!/bin/bash
sum=0
declare -a feibo
feibo=(0 0 0 0 0 0 0 0 0 0)
feibo[0]=1
feibo[1]=1
for i in 2..9
do
feibo[$i]=$((feibo[$i-1]+feibo[$i-2]))
done
for j in 0..9
do
sum=$(($sum+$feibo[$j]))
echo $feibo[$j]
done
echo "sum=$sum"
这个是个很常规的问题,首先定义一个sum和还有10个数据的数组首先全部设置为0,然后将第一第二项设置为1并利用一个for循环对数组元素进行赋值。最终进行输出即可。关于斐波那契数列的问题有很多种解法可以见我之前的一篇文章斐波那契数列两种算法实现(循环,递归)_斐波那契数列循环算法_用编程写诗的博客-CSDN博客
拓展实验
1. Shell编程实现指定输入的加法,比如输入100,计算1+2+3+…+100的和。
#!/bin/bash
#1+2+3+4+.....n等于多少?
echo -n "input: "
read n
sum=0
i=1
while [ $i -le $n ]
do
sum=$(($sum+$i))
i=$(($i+1))
done
echo the value is:$sum
首先设置一个提示输出提示用户输入数据,然后只要i的值不小于n的值就进行sum相加并且i也相应的进行加1最终可以得到结果。
2.Shell编程判断指定文件夹下文件的数量。
#!/bin/bash
cd $1
filenum=0
for i in $( ls )
do
if [ -f $i ]
then filenum=$(($filenum+1))
fi
done
echo "The num of files is $filenum"
首先传入要进入文件夹然后cd $1即可进入。最开始设置文件数量为0然后利用ls命令让i从目录中的第一个文件到最后一个文件然后进行if判断只要是文件就让filenum进行加1最终输出即可。
3.Shell编程判断给定年份是否为闰年。
#!/bin/bash
echo "请输入年份"
read year
if [ $(($year%4)) -eq 0 -a $(($year%100)) -ne 0 -o $(($year%400)) -eq 0 ]
then
echo "$year是闰年!"
else
echo "$year不是闰年!"
fi
这个核心就是一个判断语句,进行输入一个年份然后进行判断,只要它是4的倍数并且不是100的倍数或者是400的倍数即可判断是闰年,这里-a相当于&&-o相当于||。
4. Shell编程实现9×9乘法表。
#!/bin/bash
for i in 1..9
do
for j in 1..9
do
if [ $j -le $i ];then
echo -n "$j"
echo -n x
echo -n "$i=$[i*j] "
fi
done
echo
done
这个程序也是很简单的也就是简单的循环嵌套而已,利用两个循环一个表示行数即被乘数一个表示乘数从1到行数这样相乘即可。我在这里多了一个echo -n x是因为我想让输出是1x1=1这样而不是1*1=1这样但是x咋shell程序设计里面是比较特殊的我不能把这三句话写成一句话只能拆开。如可以写成一句话欢迎指正。
5.Shell编程实现批量修改文件扩展名,比如将.txt文件修改为.doc文件。
#!/bin/bash
cd $1
for i in `ls *.$2`
do
mv $i $i%.*.$3
done
这就是单纯一个mv命令即可。先cd进入需要的文件夹,利用传入的参数第二个表示源文件扩展名,第三个表示修改为的文件扩展名。直接利用ls命令找到所有的第二个位置参数的文件扩展名然后转为第三个位置参数的文件扩展名。(%表示从右向左匹配删除位于%右侧通配符匹配的字符串,即i%.*就会将.也就是扩展名和.一起删除例如1.txt就会只剩下1)
Linux实验 Shell程序设计
Linux实验 Shell程序设计
1. 读取一个整数n,输出斐波那契数列的前n项及它们的和
问题分析
斐波那契数列,指的是这样一个数列:1、1、2、3、5、8、13、21、34、……在数学上,斐波那契数列以如下被以递推的方法定义:
F(0)=0,F(1)=1
F(n)=F(n - 1)+F(n - 2)(n ≥ 2,n ∈ N*)
使用三个变量的方法计算,初始情况下:a1=1 a2=1 a3=0 sum=0
通过循环计算a3的值,并且更新a1和a2的值,每计算出一项,把新的项的值加入到sum中
程序代码
#!/bin/bash
# 存放第一个参数的值
num=$1
# 第一个数
a1=1
# 第二个数
a2=1
# 存放下一个数
a3=0
# 记录和
sum=2
# 如果没有输入参数,则直接结束脚本
if [ $# -eq 0 ]; then
exit 1
fi
# 如果输入的参数是1
if [ $num -eq 1 ]; then
# 输出斐波那契数列的第一项和和
echo -ne "fib:" $a1 "\\n"
echo -ne "sum:" 1 "\\n"
# 如果输入的参数是2
elif [ $num -eq 2 ]; then
# 输出斐波那契数列的第一项和和
echo -ne "fib:" $a1 " " $a2 "\\n"
echo -ne "sum:" 2 "\\n"
# 如果输入的参数是2以上的数字
else
echo -ne "fib:" $a1 " " $a2 " "
# for循环计算
for (( i=3; i<=$num; i++)) do
# 计算出下一个数
let a3=$a2+$a1
echo -n $a3 " "
# 把结果加入和中
let sum=$sum+$a3
let a1=$a2
let a2=$a3
done
echo -ne "\\nsum:" $sum "\\n"
fi
2. 读取若干输入,把第二个位置参数及其以后的各个参数指定的普通文件复制到第一个位置参数指定的目录中
若第一个参数指定的目录不存在,则创建它;若存在且为普通文件,则删除该文件,并创建为目录;若存在且为目录,则清空这个目录
第二个参数及其以后的参数,若为普通文件则复制到第一个参数指定的目录,否则忽略
问题分析
首先根据题目,判断第一个参数指定的目录的状态
测试 | 为ture的条件 |
---|---|
[ -e file ] | 文件存在 |
[ -d file ] | 文件存在,且为目录文件 |
[ -f file ] | 文件存在,且为普通文件 |
程序代码
#!/bin/bash
# 文件参数个数
parameter_number=$#
# 要移动到的文件路径
file_path=$1
# 没有任何参数
if [ $# -eq 0 ]; then
exit 1 # 退出
fi
# 如果第一个参数指定的目录不存在
if [ ! -d $file_path -a ! -f $file_path ]; then
mkdir $file_path # 创建目录
# 如果为普通文件
elif [ -f $file_path ]; then
rm -f $file_path # 删除它
mkdir $file_path # 创建目录
# 如果目录存在
elif [ -d $file_path ]; then
rm -f $file_path/* # 清空
fi if [ $# -gt 1 ]; then
# 循环复制文件到目录下面
for (( i=2; i <= $parameter_number; i++)); do
# 获取第二个未知参数的值,第二个位置开始,是要移动的文件
file_name=$2
# 判断该文件是不是普通文件
if [ -f $file_name ]; then
# 如果是就移动
mv "$file_name" "$file_path/"
fi
# 将每个位置参数的值向前挪一个
shift
done
fi
3. 读取/etc目录下的所有普通文件,寻找其中最长的一行,输出其内容和长度(忽略/etc的所有子目录)
问题分析
通过ls命令,可以列出/etc目录下的所有文件的名字,将ls命令的结果作为while循环中的输入条件,即从结果中一条一条的取数据,如果这个数据是普通文件,就计算出长度和记录下字符串,提前设置一个长度最大值变量和记录最大长度字符串的变量,比较计算出的长度和长度的最大值,如果最大值小于当前的长度,就更新最大值和字符串
程序代码
#!/bin/bash
# 用来存放最大长度的变量
maxLength=0
# 用来存放最大字符串的变量
maxString=""
# 将ls结果作为输入, 依次放入到line中
ls /etc | while read line; do
# 文件在/etc目录下,所有要加入父目录,否则是当前目录的文件
path="/etc/$line"
# 如果这个文件是普通文件
if [ -f $path ]; then
# length中存放每一条记录的长度
length=$#line
# 如果当前记录的长度大于最大记录的长度
if [ $length -gt $maxLength ]; then
# 改变最大长度和最大字符串
let maxLength=$length
maxString=$line
# 将maxString的内容重定向到(写到)一个tp文件中
# tp不存在就创建,存在就覆盖
# tp文件用来存放记录下来的最大字符串和长度
echo $maxString > tp
# 追加写入
echo -n "长度:" >> tp
# 追加写入
echo $maxLength >> tp
fi
fi
done
echo /etc下最长文件是:
# 输出tp文件的内容
cat < tp
# 删除tp文件
rm tp
4. 依次读取年、月、日三个参数(如1991 2 14),计算它距离今天的天数。
能被4整除但不能被100整除,或能被400整除的年为闰年
使用date +”%-Y”,date +”%-m”和date +”%-d”可获得当前的年月日
问题分析
计算两个时间之间的天数,可以从年份、月份、天数依次比较
首先,年份和月份一样,天数作差即可
其次,年份相同,月份不同,计算相差的月份,把相差的完整的月份的天数计算出来,再计算不完整的天数
最后,年份不同月份不同,还是计算完整月份的天数,还要计算完整年份的天数,最后把这些天数和不完整的天数加在一起,就能得到最后的相差的天数
程序代码
#!/bin/bash
# 如果输入的参数不是3个
if [ ! $# -eq 3 ]; then
# 直接退出
exit 1
fi
# 记录差
dayGap=0
monthGap=0
yearGap=0
# 获取当前日期
currentTime=`date +%Y-%m-%d`
# 提取年月日 2021-12-19
year=$currentTime:0:4
month=$currentTime:5:2
day=$currentTime:8:2
# echo $year $month $day
# 判断一年是否是闰年
function isLeapYear ()
t=$1
let prv=$t%4
let nxt=$t%100
let aft=$t%400
if [ $prv -eq 0 -a ! $nxt -eq 0 -o $aft -eq 0 ]; then
echo 1
else
echo 0
fi
function Month ()
pMonth=$1
pYear=$2
pDay=0
provisional=`isLeapYear $pYear` # echo "provisional=$provisional $pYear" >> tp
if [ $provisional -eq 1 ]; then
case $pMonth in
1) pDay=31;;
2) pDay=29;;
3) pDay=31;;
5) pDay=31;;
7) pDay=31;;
8) pDay=31;;
10) pDay=31;;
12) pDay=31;;
*) pDay=30;;
esac
else
case $pMonth in
1) pDay=31;;
2) pDay=28;;
3) pDay=31;;
5) pDay=31;;
7) pDay=31;;
8) pDay=31;;
10) pDay=31;;
12) pDay=31;;
*) pDay=30;;
esac
fi
echo $pDay
function yearDay ()
dd=0
provision=$1
for ((i=1; i<=12; i++)); do
let c=`Month $i $provision` # echo $c >> temp
let dd=$dd+$c # echo "dd=$dd" >> temp
done
echo $dd
# 获取输入日期
inputYear=$1
inputMonth=$2
inputDay=$3 # echo $inputYear $inputMonth $inputDay
# 两个日期在同一年
if [ $year -eq $inputYear ]; then
# 同一个月
if [ $inputMonth -eq $month ]; then
let dayGap=$day-$inputDay
# 不同月
else
provisionalYear=$inputYear
let monthGap=$month-$inputMonth
let $monthGap=$monthGap-1
for (( i=$monthGap; i>0; i--)); do
let temp=$inputMonth+$i
let dayGap=$dayGap+`Month $temp $provisionalYear`
done
a=`Month $inputMonth $provisionalYear`
let a=$a-$inputDay
let dayGap=$dayGap+$a
let dayGap=$dayGap+$day
fi
# 不同年
else
# 计算输入年份和现在年份之间空白年的总天数
let yearGap=$year-$inputYear # echo "yearGap=$yearGap" >> temp
for ((i=$yearGap-1; i>0; i--)); do
let provisionalYear=$inputYear+$i # echo "provisionalYear=$provisionalYear" >> temp
for ((j=1; j<=12; j++)); do
a=`Month $j $p provisionalYear`
let dayGap=$dayGap+$a
done
done
# 计算现在年份还有多少天
provisionalYear=$year
for ((i=1; i<$month; i++)); do
let a=`Month $i $provisionalYear`
let dayGap=$dayGap+$a
# echo "dayGap=$dayGap" >> temp
done
let dayGap=$dayGap+$day
# 计算输入年剩余天数
provisionalYear=$inputYear
a=0
for ((i=1; i<$inputMonth; i++)); do
let b=`Month $i $provisionalYear`
let a=$a+$b # echo "dd1=$a" >> temp
done
let a=$a+$inputDay
let b=`yearDay $inputYear` # echo $b
let b=$b-$a
let dayGap=$dayGap+$b
fi
echo "相距$dayGap天"
以上是关于燕山大学Linux实验shell程序设计的主要内容,如果未能解决你的问题,请参考以下文章
合肥工业大学Linux实验三Linux 下的 shell 编程