shell脚本练习题

更新时间:2023-11-25 03:50:01 阅读量: 教育文库 文档下载

说明:文章内容仅供预览,部分内容可能不全。下载后的文档,内容与下面显示的完全一致。下载之前请确认下面内容是否您想要的,是否完整无缺。

shell脚本例子集锦(习题总结)

练习一:写一个脚本

1.设定变量FILE的值为/etc/passwd

2.依次向/etc/passwd中的每个用户问好,并且说出对方的ID是什么 形如:(提示:LINE=`wc -l /etc/passwd | cut -d\ Hello,root,your UID is 0. 3.统计一个有多少个用户 答案一:#!/bin/bash

file=\

LINES=`wc -l $file | cut -d\ for I in `seq 1 $LINES`;do

userid=`head -$I $file | tail -1 |cut -d: -f3` username=`head -$I $file | tail -1 |cut -d: -f1` echo \ done

echo \ 答案二:#!/bin/bash file=/etc/passwd let num=0

for I in `cat $file`;do

username=`echo \ userid=`echo \

echo \ num=$[$num+1] done

echo \练习二:写一个脚本

1.切换工作目录至/var

2.依次向/var目录中的每个文件或子目录问好,形如:

(提示:for FILE in /var/*;或for FILE in `ls /var`;) Hello,log

3.统计/var目录下共有多个文件,并显示出来 答案:#!/bin/bash cd /var let num=0

for I in `ls /var/*`;do echo \ num=$[$num+1] done

echo \练习三:写一个脚本

1.设定变量file的值为/etc/passwd

2.使用循环读取文件/etc/passwd的第2,4,6,10,13,15行,并显示其内容

3.把这些行保存至/tmp/mypasswd文件中 答案:#!/bin/bash

file=\

for I in 2 4 6 10 13 15;do exec 3>/tmp/mypasswd

line=`head -$I $file | tail -1` echo \ echo \ exec 3>&- done

练习四:写一个脚本

传递两个整数给脚本,让脚本分别计算并显示这两个整数的和,差,积,商

答案如下:vim test.sh #!/bin/bash

echo \(表示输出第一个数) echo \(表示输出第二个数) echo \(输出两数之和) echo \(输出两数之差) echo \(输出两数之积) echo \(输出两数之商)

:wq (表示保存并退出vi编辑器) chmod +x test.sh (给test.sh执行的权限) ./test.sh 2 3 (传递两个参数并执行脚本

作业一:写一个脚本:

1.创建目录/tmp/scripts 2.切换工作目录至此目录中

3.复制/etc/pam.d目录至当前目录,并重命名为test

4.将当前目录的test及其里面的文件和子目录的属主改为redhat 5.将test及其子目录中的文件的其它用户的权限改为没有任何权限 答案:

#!/bin/bash

mkdir -v /tmp/scripts cd /tmp/scripts

cp -r /etc/pam.d ./test chown -R redhat ./test chmod -R o=--- ./test 作业二:写一个脚本

1.显示当前系统日期和时间,而后创建目录/tmp/lstest 2.切换工作目录至/tmp/lstest 3.创建目录a1d,b56e,6test

4.创建空文件xy,x2y,732

5.列出当前目录下以a,x或者6开头的文件或目录

6.列出当前目录下以字母开头,后跟一个任意数字,而后跟任意长度字符的文件或目录 答案:

#!/bin/bash date

mkdir -pv /tmp/lstest cd /tmp/lstest

mkdir a1d b56e 6test touch xy x2y 732 ls [ax6]*

ls [[:alpha:]][[:digit:]]*

作业三:写一个脚本

添加10个用户user1到user10,但要求只有用户不存在的情况下才能添加

答案:

#!/bin/bash

for I in `seq 1 10`;do

cut -d: -f1 /etc/passwd |grep \2>>/tmp/etc.err || useradd user$I

done

作业四:写一个脚本

通过ping命令测试192.168.0.151到192.168.0.254之间的所有主机是否在线

如果在线,就显示“ip is up” 如果不在线,就显示“ip is down” 答案: #!/bin/bash

for I in `seq 151 254`;do ping -c1 -w1 192.168.0.$I &>/dev/null && echo \is up\|| echo \ done

例题:

shell1.sh 显示日期和时间。

#!/bin/bash

echo “current time is `date`” //date要加反引号

shell2.sh 显示文件名,并显示位置参数(执行时带一个参数)。(①$0

是一个特殊的变量,它的内容是当前这个shell程序的文件名;②$1是一个位置参数,位置参数之间用空格分隔,shell取第一个位置参数替换程序文件中的$1,第二个替换$2,依次类推。)

#!/bin/bash

echo “the program name is $0” //$0是一个特殊的变数 echo “the first para is $1” //$1是一个位置参数

echo “the program exit” //执行时带一个参数 如./shell2.sh abcd

shell3.sh 判断并显示位置参数

#!/bin/bash if [ -d “$1”];then

echo “$1 is directory ,existed” else

echo “$1 does not exist ,now create it” mkdir $1

echo “$1 is created”

fi //执行时带一个参数

shell4.sh 问候用户

#!/bin/bash

user=`whoami` case $user in teacher) echo “hello teacher”;; root) echo “hello root”;; *) echo “hello $user,welcome” esac

1、 求1+2+3+...+100的和是?

#!/bin/bash SUM=0

I=0

while [ $I -le 100 ] do

SUM=$((SUM+I)) I=$((I+1)) done

echo \由1+2+3+...+100的和是:$SUM\

2、(基训十一) 在根目录下有四个文件m1.txt,m2.txt,m3.txt,m4.txt,用Shell编程,实现自动创建m1,m2,m3,m4四个目录,并将m1.txt,m2.txt,m3.txt,m4.txt四个文件分别拷贝到各自相应的目录下。

#!/bin/bash cd /

touch m1.txt m2.txt m3.txt m4.txt I=1

while [ $I -le 4 ] do

mkdir m$I cp m$I.txt m$I I=$((I+1)) done

3、(基训十二) 编写一个名为myfirstshell.sh的脚本,它包括以下内容。a) 包含一段注释,列出您的姓名、脚本的名称和编写这个脚本的目的。

b) 问候用户。 c) 显示日期和时间。 d) 显示这个月的日历。 e) 显示您的机器名。

f) 显示当前这个操作系统的名称和版本。 g) 显示父目录中的所有文件的列表。

h) 显示root正在运行的所有进程。 i) 显示变量TERM、PATH和HOME的值。 j) 显示磁盘使用情况。 k) 用id命令打印出您的组ID。 m) 跟用户说“Good bye”

#!/bin/bash

# 09嵌入 5号 贾德进 myfirstshell.sh shell的简单编程 user=`whoami` case $user in root)

echo \teacher)

echo \*)

echo \esac

echo \日期和时间: `date`\echo \本月的日历: `cal`\

echo \本机的机器名:`uname -n`\

echo \当前这个操作系统的名称和版本:`uname -s;uname -r`\echo \父目录中的所有文件的列表:`ls ../`\echo \正在运行的所有进程:` ps -u root`\echo \变数TERM的值:$TERM\echo \变数PATH的值:$PATH\echo \变数HOME的值:$HOME\echo \磁盘的使用情况:`df`\

echo \用id命令打印出你的组ID:`id -g`\echo \

4、(基训十三) 设计一个Shell程序,在/userdata目录下建立50个目录,即user1~user50,并设置每个目录的权限为 rwxr-xr—

#!/bin/bash cd /userdata

I=1

while [ $I -le 50 ] do

mkdir -p userdata/user$I chmod o-x user$I I=$((I+1)) done

5、(基训十四) 编写shell程序,实现自动删除50个用户账号的功能。账号名为stud1至stud50。

#!/bin/bash cd /userdata I=1

while [ $I -le 50 ] do

mkdir -p userdata/user$I chmod o-x user$I I=$((I+1)) done

6、(基训十四) 设计一个shell程序,备份并压缩/etc目录的所有内容,存放在/root/bak目录里,且文件名为如下形式yymmdd_etc,yy为年,mm为月,dd为日。

#!/bin/bash

DIRNAME=`ls |root|grep bak ` if [-z $DIRNAME ]; then mkdir /root/bak cd /root/bak fi

YY=`date + %y` MM=`date + %m`

DD=`date + %d`tar czvf ${YY}${MM}${DD}_etc.gz /etc echo \

7、(基训十四) 某系统管理员需每天做一定的重复工作,请按照下列要求,编制一个解决方案:

(1)在下午4 :50删除/abc目录下的全部子目录和全部文件;

(2)下午5:50将/data目录下的所有目录和文件归档并压缩为文件:backup.tar.gz;

(3)在下午5:55将IDE接口的第二个逻辑分区卸载。

// 采用: vi pram.cron

#(1) 在下午4:50删除/abc目录下的全部子目录和全部文件; 50 16 *** rm -rf /abc/*

#(2) 下午5:50将/data目录下的所有目录和文件归档并压缩为文件:backup.tar.gz;

50 17 *** tar czvf back.tar.gz /data

#(3) 在下午5:55将IDE接口的第二个逻辑分区卸载. 55 17 *** umount /dev/hda6

// 执行:crontab pram.cron

==========================================================

设计一个Shell程序,在/userdata目录下建立50个目录,即user1~user50,并设置每个目录的权限,其中其他用户的权限为:读;文件所有者的权限为:读、写、执行;文件所有者所在组的权限为:读、执行。

程序实现及注释如下:

#! /bin/bash #adddir.sh i=1

#while循环 while [ $i -le 50 ] do

#利用 test命令 [ -d /userdata ]:判断/userdata是否存在,如果存在直接创建子目录,不#存在先创建/userdata再创建子目录。

if [ -d /userdata ] then

#mkdir -p的意思是:无论父目录/userdata存在与否,都会创建/userdata/user$i mkdir -p /userdata/user$i else

mkdir /userdata

mkdir -p /userdata/user$i fi

#根据题目的意思:/userdata/user$i应该是具有754权限,所以利用chmod赋权限。

chmod 754 /userdata/user$i i=$(($i+1)) done

函数in_path:判断传入文件是否可执行,若可执行(且存在)返回0, 否则返回1;

分析:为测试传入文件是否在PATH所有的目录中,需取得PATH中的每个路径,可用循环,但需要设定环境中的分隔符(借助环境变量IFS)为 PATH中的分隔符冒号”:”

注:$IFS 输入分隔符. 当shell读取输入数据的时候,会把一组字符看做是单词之间的分隔字符,它们通常

是空格,制表符,和换行符.

函数调用方式为 : in_path filename

in_path() {

cmd=$1 retval=1

# $1为函数的参数1,以此类推

#定义返回值变量

#设置新的IFS,并保存原来的以恢复使用

oldIFS=$IFS IFS=:

for directory in $PATH #for循环结构二: for – in do }

注:1.函数的结构, 没有形参

2.变量的引用需要符号$,而变量的定义或赋值则不需要。 3.赋值要无间隙, 条件要间隙

改进: 1.将路径、分隔符均作为函数的参数传入,应用得到扩展。

if [ -x directory/$cmd ] ; then #if条件语句之 同行表示 以分号隔开

retval=0 # -x 判断文件有是否有可执行权限

done

done

IFS=$oldIFS return retval

#恢复原来IFS,

补充,in_path函数不能对绝对路径的文件处理,需写个函数对这一情况单独处理 checkForCmdInPath() {

var=$1

#首先判断传入的非空串是否为绝对路径,即检测第一个字符是不是‖/‖,如果是,直接测 –x if [ $var != ―‖ ] ; then # 条件等价于 -n $var }

注:此函数让人一头雾水,详解如下:

fi

if [ ―${var%${var#?}}‖ = ?/‘ ] ; then #等价于 $(echo $var | cut -c1)

if [ ! -x $var ] ; then

return 1 #not found or not executable

fi

elif ! inpath $var ; then fi

return 2 #not found in PATH

1) 表达式${var%${var#?}}作匹配用,分解为 ${var%expr} ${var#expr} ,expr为正则表达

式(? 匹配单一字符)

后者(带#的)返回 expr与var匹配成功位置之后的所有内容,此处为var中第一字符之后的所有。

前者(带%的)返回 expr与var匹配成功位置之前的所有内容,此处应为 var的第一个字符。 等价于 $(echo $var | cut c1) 即取第一字符。

等价于 ${var:beginpos:size} 中beginpos=0,size=1时的结果。

var的符号放在外面了,假设$var为$1,则表达式表示为 ${1%${1#?}}

shell中的if条件可以是 表达式(需加方括号[]),另外还可以是命令或函数(不需方括号), 当命令执行成功时会后继执行具体操作,经测试,C语言中所说的true在shell中 用0表示,即if 0,才执行then,因为linux下的程序实现都是当返回0时表执行成功。 3) 若函数中没有返回值,则它默认返回0,表执行成功。

函数的编写若遵从以上的原则, 则对条件的理解 依旧像C语言中的TRUE,FALSE一样理解

============== 完善程序代码 ===================================== #!/bin/bash in_path()

... # 函数实现区域 处理不路径 返回0表找到、可执行, 否则返回1

###############################

checkForCmdInPath()

... # 函数实现区域 处理带路径和不带路径的 返回1表没找到或不可执行,返回2表没找到。默认0表找到

################################ ##### 代码执行起始位置 ############## if [ $# -nq 1 ] ; then fi

# 调用函数,并经第一个参数传给函数 checkForCmdInpath $1

# 对函数返回的结果进行判断 $? 为函数的返回值,

case $? in # case 控制结构的格式,注意红色部分。

0) echo ―found in PATH‖

;;

1) echo ―not found or not executable‖ ;; 2) echo ―not found‖

;; # *) ;; 类似于C语言中的

echo ―Usage: $0 command‖ #$0 表此执行文件 (具体内容 以 执行exit 0

2) 关于if的条件判断与C语言中的理解不一致,反映在上述的 elif语句中的条件。理解如下:

此文件时的输入串为准)

remainder=$((thousand00)) while [ ${#remainder} –lt 3 ];do

#${#remainder} # 避免remainder

为remainder串的长度

remainder=0$remainder 为00x时的丢0情况。

done

thousand=$(($thousand/1000))

#以下四句可用一句表示:result=‖${TD:=”,”}$remainder$result‖ # 上面蓝色部分表:若TD非空则返回TD,否则将”,”赋给TD.

if [ –z $TD ] ; then # 判断用户是否自定义整数分隔符, 若 空

TD=, fi result=‖$TD$remainder$result‖ 顺序

done

# 与分隔符合成串。 注意

}

if [ –n $thousand ]; then # 若 非空

result=‖$thousand$result‖

elif [ ${result%${result#?}} = ―$TD‖ ]; then result=‖${result#?}‖ fi

echo $result

脚本标志参数处理命令: getopts ―‖ var 带两个参数,第一个参数为带解析的 参数标志序列串(如-f,-c等), 以冒号(:)分隔各标志,且以冒号:结束

第二个参数为:变量,每执行一次存放 参数标志序列串中的一个标志字符 返回值:未解析结束返回0,解析结束返回1

涉及的内定变量:$OPTARG 每次解析标志对应的参数值 便默认存放在此变量内。

$OPTIND 当各标志处理无误情况下,该数值指示当前用到的最大位置参数($#)。

此值使用容易出错(若参数的判断不完善时), 还不如用 $#

另外 $1, $2, $3, $4, ===> 此时 $# 等于 4, 当执行shift 1 时, 各个位置参数的值向一次向左右1次,此时 $1的值 为原$2的值

当执行shift 2 时, 各个位置参数的值向一次向左右2次,此时 $1的值 为原$3的值。

完整代码 ------- nicenumber.sh --------------------------- nicenumber()

..... # 函数实现部分

#处理脚本标志参数

while getopts ―d:t:‖ opt do

case $opt in # $opt 为 具体的标志字符 d ) DD=‖$OPTARG‖ ;; # $OPTARG 为标志指定的参数值 t ) TD=‖$OPTARG‖ ;; * ) echo ―no arg-flag: $opt‖ >&2 ; exit 1 esac done

# 当脚本接收如此多的参数时,$1将不代表脚本最终要处理的大数字,所以做如下操作。

shift $(($OPTIND - 1))

nicenumber $1 exit 0

----------------------------------------------------------------

扩展:

1.不同国家整数与小数的分隔符不同,使脚本能够处理各种整数与小数各种分隔符情况。在传给脚本参数时需指定标志-d

程序中仅需在 分隔 整数与小数部分略修改为

integer=$(echo $1 | cut ―–d${DD:=‖.‖‖ –f1 ) decimal=$(echo $1 | cut ―–d$DD‖ –f2 )

2.另外,可以在程序执行之前分别初始化DD,TD默认值。

3. 检测传给脚本的大数值中是否含有 非法的整小数分隔符,即存在与用户指定或默认分隔符不同的符号。

方法:删除其中所有数字,看剩下的内容,若不空且不等于$DD,则非法 separator=‖$(echo $1 | sed ?s/[[:digit:]]//g‘)‖

if [ -n $separator && ―$separator‖ != ―$DD‖ ];then # 蓝色部分可用 –a 表示 exit 1 fi

5. 检测 输入整数的合法性,可负数(-1, -2均合法), 可以指定传入整数范围,不在范围内则报错。

参数:1或3个, 当3个时,后两个为范围。 合法性:正负数的判断,范围的判断。 validint() {

integer=$1 min=$2 max=$3 # 判断传参的合法性,以下判断是错误的,因为不管参数是否为空,实际上都传了三个参数。

if [ $# -eq 0 ];then # 改成判断$1的内容是否为空,就可以了

echo ―you couldn‘t do nothing>‖&2 return 1 fi #判断是否为负数,第一个字符 是否为 –, 如是,则判断后面的是否为整数。若非负,则判断是否为整数

if [ ―$(echo $1 | cut –c1)‖ = ―-‖ ]; then signed=‖-‖

integer=‖${integer#?}‖ fi

# 如果就是一个符号 -,则也是非法的 if [ -z ―$integer‖ ]; then

echo ―Invalid input, just a ―-‖ is not allowed‖>&2 #注意:>&2 三个字符紧连。 return 1 fi

# 如果非纯数字构成,则非法。

if [ -n ―$(echo $integer | sed ?s/[[:digit:]]//g‘)‖ ] ; then echo ―Invalid integer, it includes some char but digit‖>&2 return 1 fi

integer=‖$signed$integer‖

# 范围判断,注意当 min 和 max 为空时(即未传范围),我设定其为$integer,如此判断就不会出错。

if [ $integer –lt ${min:=$ingeger} ];then echo ―$integer is too small, it should greater than $min‖>&2 return 1 fi

if [ $integer –gt ${max:=$integer} ];then echo ―$integer is too large, it should little than $max‖>&2 return 1 fi

return 0

}

--------------执行代码------------ #!/bin/bash validint() .....#

if validint ―$1‖ ―$2‖ ―$3‖; then

echo ―your input is valide‖

fi

注:if [ ! -z $min -a \为AND表达式,但在shall脚本中,当第一个条件为false时,不能保证第二个条件不被测。 而将if条件改写成两层嵌套的if语句后,当第一个为false时,则第二个一个不会被测。

6. 检测浮点数的合法性。 参数:1个浮点数

合法性: 不支持科学表示法,支持带符号 -1.2 -.75均合法。

思路:首先要判断是整数还是浮点数,只是一种可能性的判断,即判断有没有 点

有点的情况:依据“.”劈成两半,前半为合法整数。后半必须为 >=0 的整数。

需调用上一例中的判断整数合法性的validint()函数

无点的情况:基本做整数判断处理 函数:

validfloat() {

fvalue=$1

# 保证传入参数非空

if [ -z ―$fvalue‖ ] ; then

echo ―you input nothing‖>&2 return 1 fi

# 判断有点否?(清除点以外的字符,看看结果是否为空)

if [ -n $(echo $fvalue | sed ?s/[^.]//g‘) ] ; then integer=‖$(echo $fvalue | cut –d. f1 )‖ decimal=‖$(echo $fvalue | cut –d. f2 )‖

//判断整数部分的合法性,当仅为 – 时,把它看成0,免去判断 if [ ―$integer‖ != ―-‖ ] ; then if ! validint ―$integer‖ ; then

echo ―part before dot $integer is not valide!‖>&2 return 1 fi fi

//判断小数部分整数的合法性。必须>=0, 当为空时不判断。 if [ -n ―$decimal‖ ] ; then

if ! validint ―$decimal‖ 0 ; then

echo ―part after dot $decimal is not valide!‖>&2 return 1 fi fi else

# 没有点,就当作整数处理

if validint ―fvalue‖ ; then

echo ―your input is a integer‖>&2 return 1 fi fi

}

-----------------完整代码 validfloat ---------------------- #!/bin/bash . validint validfloat()

#引用别的文件定义的函数。

.... # 实现部分

if validfloat $1 ; then

echo ―$1 is a valid floating-point value‖ fi

exit 0

-------------------------------------------------------------

}

-----------------完整代码 validfloat ---------------------- #!/bin/bash . validint validfloat()

#引用别的文件定义的函数。

.... # 实现部分

if validfloat $1 ; then

echo ―$1 is a valid floating-point value‖ fi

exit 0

-------------------------------------------------------------

本文来源:https://www.bwwdw.com/article/xg0t.html

Top