实验9:shell及shell编程

1、实验目的

1)sed的使用;

2)awk的应用;

3)shell及shell编程;

4) 与用户启动相关的文件及使用。

2、实现设备

一台装有Windows操作系统和Linux机系统的微机或服务器。

3、实验方法与注意事项

1)由于是以root用户工作的,权力很大,请不要在系统内做对系统或对其他用户不安全的事情。

2)要求每个同学登录后系统后,要在自己的家目录内容以自己(汉语拼音)名字,使用mkdir命令创建一个子目录。以后所有工作都要在自己的目录内进行。

3)认真编写实验报告

4、实验过程

1) sed命令的使用:

二,复制
    a,复制整行
        命令模式下,光标位于要复制的当前行,输入 yy 
    b,复制一个单词
        命令模式下,光标位于要复制的当前单词的第一个字母,输入 yw
三,黏贴
    命令模式下,输入 p

(1) 将ifile文件中的所有sysman替换成System Manager并输出到ofile

sed -e 's/sysman/System Manager/g' <ifile>ofile

[root@localhost gaozhen]# ls
ifile  ofile
[root@localhost gaozhen]# sed -e 's/sysman/System Manager/g' <ifile> ofile
[root@localhost gaozhen]# cat ofile
System Manager System Manager
                                                                                
System Manager System Manager
System Manager System Manager
System Manager System Manager
System Manager System Manager
System Manager System Manager
System Manager System Manager



(2) 显示ifile文件中的所有注释行

四,删除
    a,删除整行
        命令模式下,光标位于要删除的所在行,输入 dd
          b,删除一个单词
        命令模式下,光标位于要删除的单词的第一个字母,输入 dw


五,撤销
    命令模式下,输入 u

六,跳转
    命令模式下,输入 要跳转的行数,然后再输入 gg
    如:要跳转到当前文件的第150行,输入 150gg

#sed -e '/^#/!d' < ifile    #参见不执行某命令!function

#sed -e '/^[[:blank:]]*#/!d' < ifile #此比上例更有效



(3) 删除文件ifile中的空行,并将其它的内容输出到ofile:

方法①

#sed '/^$/d/^[<tab><Space>]*$/d' <ifile>ofile


[root@localhost gaozhen]# sed '/^$/d' ifile > output

[root@localhost gaozhen]# sed -i '/^$/d' ifile


#注:tab为tab键,<tab>可用\t表示,<space>为空格键。

方法②  方法①也可写为:

sed '/^$/d;/^[<tab><Space>]*$/d' <ifile >ofile      或写为

sed '/^$/d;/^[[:blank:]]*$/d' <ifile >ofile         或写为

sed '/^$/d;/^[[:space:]]*$/d' <ifile >ofile



(4)其它应用

①显示文件的前10行: (实现head [-10] file的功能)


sed -n -e '1,10p' file

[root@localhost gaozhen]# sed -n -e '1,10p' ifile


sed -e '10q' file


[root@localhost gaozhen]# sed -e '10q' ifile


②统计文件的行数:(实现wc –l功能)

sed -n -e '$=' file


[root@localhost gaozhen]# sed -n -e '$=' ifile
18

③显示文件的后10行:(实现tail -10 file功能,此为一个简单的shell脚本程序)



x=`sed -n -e '$=' t`;   y=$(($x-10));   sed -n -e "$y,\$p" t


说明:如果脚本命令较多,也可将整个脚本内容写入文件(比如e_script)中,此时命令的执行可如下进行:


sed –f e_script < ifile> ofile


2) awk命令的使用

(1) 显示系统内root的进程,它们是什么,进程号是多少

ps -ef | awk '/root/{ print $1, $2, $8}'


[root@localhost gaozhen]# ps -ef | awk '/root/{print $1,$2,$8}'


ps -ef | awk '/^[[:blank:]]*root/{ print $1, $2, $8 }'


root@localhost gaozhen]# ps -ef | awk '/^[[:blank:]]*root/{print$1,$2,$8}'


(2) 显示系统所非root用户在干什么,他们是谁?

[root@localhost gaozhen]# ps -ef | awk '!/root/{print $1,$8}'


ps -ef | awk '!/root/{ print $1, $8 }'

ps -ef | awk '!/^[[:blank:]]*root/{ print $1, $8 }' #更精确


[root@localhost gaozhen]# ps -ef | awk '!/^[[:blank:]]*root/{print $1,$8}'


(3) 使用awk计算文件infile内数字的和。


将命令编辑成脚本文件,执行脚本文件即可


awk '{ sum += $1 }; END{ print sum }' ifile


[root@localhost gaozhen]# vi ifile
[root@localhost gaozhen]# touch a.bat
[root@localhost gaozhen]# vi a.bat
[root@localhost gaozhen]# clear
 
[root@localhost gaozhen]# cat a.bat
wk '{ sum += $1 }; END{ print sum }' ifile
[root@localhost gaozhen]# file a.bat
a.bat: ASCII text
[root@localhost gaozhen]# chmod +X a.bat
[root@localhost gaozhen]# file a.bat
a.bat: ASCII text
[root@localhost gaozhen]# ./a.bat
bash: ./a.bat: 权限不够
[root@localhost gaozhen]# chmod 777 a.bat
[root@localhost gaozhen]# ./a.bat
./a.bat: line 1: wk: command not found
[root@localhost gaozhen]# cat a.bat
wk '{ sum += $1 }; END{ print sum }' ifile
[root@localhost gaozhen]# vi a.bat
[root@localhost gaozhen]# cat a.bat
awk '{ sum += $1 }; END{ print sum }' ifile
[root@localhost gaozhen]# ./a.bat
6

注:假设infile内容为数字串,且每个数字串占一行。


(4) 显示系统内已经注册(创建)的所有用户(显示/etc/passwd内的所有用户)

awk -F: '{ print $1 }' /etc/passwd   


 #-F:指定域分隔符为“:”



(5) 统计文本文件的总行数


awk 'END{ print NR }' file

3)shell编程



(1) 设计一个程序,带一个(目录)参数。实现功能:

(1)首先判断是否带有参数,若无则显示用法信息后,报错返回;

(2)带首先判断该参数是不是目录。若是则列目录的内容,否则,提示用户不是目录,则显示警告信息后报错返回。


vi显示行号/数/查询vi Linux  

在VI的命令模式下输入“:set nu” 

或者修改vi配置文件“vi ~/.vimrc”,在其中添加“set nu” 

在VI的命令模式下输入“:set nu”,就有行号了。 

但是想将这个设置写进VI的配置文件,就 
# vi ~/.vimrc 
在这个文件中,添加 
set nu 
就行了 
set nu       -- to display line no
set nonu    -- not to display line no

ctrl + g 可以知道cursor的那一行的行数

shift+g可以到最后一行。在:下输入行号,可到达对应行

g+g 到达页首

另:

ctrl + f 向前翻页

ctrl + b向后翻页



1)查找vi 文件中的内容

可以以用正则表达式,如要查询with

就可以直接输入  :/with/ 回车



2)grep的含义是“全局搜索正则表达式(RE)并打印该行”
grep 要查询的内容  查询的文件名

如:grep NW datafile    释:打印datafile中包含NW的行

[root@localhost gaozhen]# touch datafile
[root@localhost gaozhen]# vi datafile
[root@localhost gaozhen]# grep gao datafile
gaozhenfdsafdfdffdasfdsf


[root@localhost gaozhen]# cat datafile
gaozhenfdsafdfdffdasfdsf
dfadfdsfdsfds
fdasf

grep 可以从管道得到输入。

如:% ls –l | grep man

释:从列表中筛选出文件名包含man的文件,并列出

所有的元字符都当作字符本身,只代表自己。
例子:
? 打印包含San的行
grep 'San' datebook

1.作用
Linux系统中grep命令是一种强大的文本搜索工具,它能使用正则表达式搜索文本,并把匹 配的行打印出来。grep全称是Global Regular Expression Print,表示全局正则表达式版本,它的使用权限是所有用户。

4.grep命令使用简单实例
$ grep ‘test’ d*

显示所有以d开头的文件中包含 test的行。

[root@localhost gaozhen]# grep 'test' d*
datafile:test datafile
demo:test demo


$ grep ‘test’ aa bb cc
显示在aa,bb,cc文件中匹配test的行。

[root@localhost gaozhen]# grep 'test' datafile demo
datafile:test datafile
demo:test demo


$ grep ‘[a-z]\{5\}’ aa
显示所有包含每个字符串至少有5个连续小写字符的字符串的行。

[root@localhost gaozhen]# grep '[a-z]\{3\}' datafile
gaozhenfdsafdfdffdasfdsf
dfadfdsfdsfds
fdasf
wangdanli dfdfdfd
test datafile


$ grep ‘w\(es\)t.*\1′ aa
如果west被匹配,则es就被存储到内存中,并标记为1,然后搜索任意个字符(.*),这些字符后面紧跟着 另外一个es(\1),找到就显示该行。如果用egrep或grep -E,就不用”\”号进行转义,直接写成’w(es)t.*\1′就可以了。


5.grep命令使用复杂实例
假设您正在’/usr/src/Linux/Doc’目录下搜索带字符 串’magic’的文件:
$ grep magic /usr/src/Linux/Doc/*
sysrq.txt:* How do I enable the magic SysRQ key?
sysrq.txt:* How do I use the magic SysRQ key?


其中文件’sysrp.txt’包含该字符串,讨论的是 SysRQ 的功能。


默认情况下,’grep’只搜索当前目录。如果 此目录下有许多子目录,’grep’会以如下形式列出:


grep: sound: Is a directory
这可能会使’grep’ 的输出难于阅读。这里有两种解决的办法:
明确要求搜索子目录:grep -r
或忽略子目录:grep -d skip
如果有很多 输出时,您可以通过管道将其转到’less’上阅读:
$ grep magic /usr/src/Linux/Documentation/* | less
这样,您就可以更方便地阅读。


有一点要注意,您必需提供一个文件过滤方式(搜索全部文件的话用 *)。如果您忘了,’grep’会一直等着,直到该程序被中断。如果您遇到了这样的情况,按 <CTRL c> ,然后再试。


下面还有一些有意思的命令行参数:
grep -i pattern files :不区分大小写地搜索。默认情况区分大小写,
grep -l pattern files :只列出匹配的文件名,
grep -L pattern files :列出不匹配的文件名,
grep -w pattern files :只匹配整个单词,而不是字符串的一部分(如匹配’magic’,而不是’magical’),
grep -C number pattern files :匹配的上下文分别显示[number]行,
grep pattern1 | pattern2 files :显示匹配 pattern1 或 pattern2 的行,
grep pattern1 files | grep pattern2 :显示既匹配 pattern1 又匹配 pattern2 的行。


grep -n pattern files  即可显示行号信息


grep -c pattern files  即可查找总行数


这里还有些用于搜索的特殊符号:
\< 和 \> 分别标注单词的开始与结尾。
例如:
grep man * 会匹配 ‘Batman’、’manic’、’man’等,
grep ‘\<man’ * 匹配’manic’和’man’,但不是’Batman’,
grep ‘\<man\>’ 只匹配’man’,而不是’Batman’或’manic’等其他的字符串。
‘^’:指匹配的字符串在行首,
‘$’:指匹配的字符串在行 尾,


? 打印所有以J开头的人名所在的行
grep '^J' datebook

[root@localhost gaozhen]# grep '^g' datafile
gaozhenfdsafdfdffdasfdsf
gaozhe gaodfds gao??????


? 打印以700结尾的行
grep '700$' datebook


[root@localhost gaozhen]# grep '900$' datafile
fadsfdsf900



? 打印所有不包含834的行
grep -v '834' datebook

[root@localhost gaozhen]# grep -v '900' datafile



? 打印出生在12月(December)的行
grep '/12' datebook

[root@localhost gaozhen]# grep '/12' datafile
2014/12/4
? 打印工资是6位数的行,并给出行号
grep -n '[0-9]\{6,\}$' datebook

 [root@localhost gaozhen]# grep -n '[0-9]\{6,\}$' datafile
9:123456 234556


在VI的命令模式下输入“:set nu”,就有行号


#!/bin/sh

if [ $# -ne 1 ]      #check if have 1 parameter

then

       echo"Usage: $0 dir" #Diaplay Usage

       exit1            #return 1

fi

if [ -d "$1" ]           #ifis a dir;then

       ls$1/*; exit 0   #list the dir,and return 0

fi

echo "Warn: $1 is not adirectory" #Warning message

exit 2        #return2



if [ $# -ne 1 ];then
echo "Usage: $0 dir"
exit 1
fi
if [ -d "$1" ];then
                ls $1/*; exit 0
fi
echo "Warn: $1 is not a directory" 
exit 2


注:输入时可不输入注释部分。设此程序名为myls,为其增加执行权后,运行方法为:

    ./myls         #返回码为1

    ./mylsdir    #如果dir是个目录,则列其内容

    ./mylsfile       #若file是文件或不存在则给出警告后返回2




(2) 用嵌套式if-fi语句实现(1):

#!/bin/sh

if [ $# -ne 1 ]          #check if have 1parameter

then

    echo"Usage: $0 dir" #Diaplay Usage

    exit1                   #return 1

elif [ -d "$1" ]            #ifis a dir

then

    ls$1/*; exit 0          #list the dir,andreturn 0

else

    echo"Warn: $1 is not a directory" #Warning message

    exit2                   #return2

fi

 

(3) 设计一个程序,从命令行接收数值参数,并计算这些参数的和。

x=0

for y in $*

do

    x=`expr $x + $y`

done

echo "The Sum is: $x"

注:设程序名为myadd,增加执行权后,运行方法为:myadd 20 35 100 60

但是,本程序是有问题的,原因是它没有判断输入数据的合法性。下面是一个增加输入数据合法性检查的程序。

x=0

for y in $*

do

    z=`echo$y | awk '/^[[:digit:]]*$/ { print $0 }'`

    if[ -z $z ]; then

       echo-e "Invalid command line parameter: $y\a"; exit 1

    fi

    x=`expr$x + $y`

done

echo "The Sum is: $x"

(4) 设计一个程序,计算前n个正整数的和:

x=0; y=1

while true

do

    x=`expr $x + $y`

    y=`expr $y + 1`

    if [ $y -gt $1 ]; thenbreak; fi

done

echo "1+2+..+$1=$x"

注:此程序要带有1个参数作为整数n,以计算前n个正整数的和。设程序名为myadd1,则运行方法是:myadd1 10或myadd1 100等。

(5)使用bsh编程,实现以下功能:从命令接收不定数量的命令行参数,参数为程序中要处理的文本文件名,程序要判断每个参数所表示的文件名是否存在,不存在时报错,若存在则显示其文本总行数。

#!/bin/sh

if [ $# -eq 0 ]; then echo "$0:no input file!"; exit 1; fi

while [ $# -gt 0 ]

do

       if[ ! -e $1 ]; then echo "$1: dosn't exist!"; exit 1; fi

       if[ -f $1 ]; then

              echo-n "$1:";

              #以下3句中的任何一个均可,或其它能够实现此功能语句亦可

              sed -n -e '$=' $1;

              awk 'END { print NR }' $1;

              wc -l $1 | awk '{ print $1 }'

       else       echo -n "$1:i Not a textfile"

       fi

       shift

done

(6)here文档

#!/bin/sh

cmd="uname -s"; name=`whoami`

cat << !

My nameis $name, I am a student.

I studycomputer, and now I have an exam of `$cmd` OS.

!

4) 与用户登录相关文件

.bash_history        #历史文件

.bash_logout         #用户注销时要执行的文件

.bash_profile        #用户登录时要执行的文件

.bashrc              #用户登录时要执行的文件,由.bash_profile调用

/etc/bashrc          #用户登录时要执行的文件,由.bashrc调用

/etc/profile         #用户登录时要执行的文件,由/etc/bashrc调用

/etc/profile.d/*     #用户登录时要执行的文件,由/etc/profile调用

用户可以根据需要修改,它们的内容。

以下为一个菜单程序(可取名为sh_add),可将它加在用户.bash_profile的最后,当用户登录时,若成功则直接执行此程序而进入菜单控制,当用户退出菜单时直接注销自己,回到login登录界面。

trap '' 12 3 15  #trap the signal 1,2,3,15

func1( ){

    echo -e "\n\n\t\t\tThist is Function 2Demontration!"

    echo -e    "\t\t\t1111111111111111111111111111111!"

}

func2( ){

    echo -e "\n\n\t\t\tThist is Function 2Demontration!"

    echo -e "\t\t\t2222222222222222222222222222222!"

}

whiletrue

do

       clear

       echo -en "

\t+-----------------------------------------------------+\n\

\t|                                                               |\n\

\t|      1.func1   2.func2    q.quit                          |\n\

\t|                                                               |\n\

\t+-----------------------------------------------------+\n\

\t\t\tPleaseget Select 1,2 or q:"

       read x

       case $x in

       1)

           func1;;

       2)

           func2;;

       s|S)

           trap 1 2 3 15

           break;;

       Q|q)

           exit 0;;

       *)

           echo -e "\a";;

       esac

       echo -en "\n\t\t\tPress Enter Key toContiune:"

       read x; clear

done

注意:应$HOME/.bash_profile的最后加入一行:

    .  sh_add

让该程序在当前shell内运行。

当此文件放在$HOME/.bash_profile内后,X-Windows将无法正常启动。注释掉此命令所在行后可恢复X-Windows正常启动。也可以通过在以上代码中的while true加入根据终端号进行判断办法来实现:具体做是当用户在/dev/tty1~/dev/tty12是使用本程序时执行while true语句段,否则跳过while true;do … done语句段,什么都不做。(由用户自己完成)

当然,用户也可以修改$HMOE/.bash_profile干别的事情,比如设置环境变量等。此方法在用户登录控制设置时是非常有用的。

请实验者关注程序中两个trap语句的作用。S|s的功能是什么?

4、实验报告的内容与书写

以书面形式记录下你的每一步过程,包括输入、输出信息,遇到的问题和解决的办法。

 

Logo

更多推荐