Linux程序设计之shell

一、Shell简介
        Shell是一个作为用户与linux操作系统之间的接口的程序,它允许用户向操作系统输入需要执行的命令。Shell执行shell程序,这些程序通常称为脚本,它们是运行时解释执行的。
            
       版本查询:/bin/bash–version
       历史版本

sh(Bournce)      源于UNIX早期版本的最初的shell
csh、tcsh、zsh    C shell及其变体,是继bash和Korn shell之后的第三个最流行的sehll
ksh、pdksh        Korn shell和它的公共域兄弟pdksh由David Korn编写,是许多商业版本UNIX的默认shell
bash	          来自GNU项目的Bourne Again Shell是linux主要的shell。优点是可以免费获取其源代码,即使没有运行它,它可能已经移植到系统中
    注:大多数linux发行系统中,默认的shell程序/bin/sh实际上是/对程序bin/bash的一个连接
二、Shell Script简介
    Shell script是利用shell的功能所写的一个程序,它是使用纯文本文件,将一些shell的语法与命令写在里面,搭配正则表达式、管道命令和数据重定向等功能,已达到我们的目的。Shell script用在系统管理上面是很好的一项工具,但是用在处理大量数值运算上,就不够好了。因为shell script的速度较慢,且使用的cpu资源较多,造成主机资源的分配不良。
    Shell script优点
    1、自动化管理的依据。例如系统每天都会自动查询登陆文件、追踪流量、监控用户主机状态、各项硬件设备状态等工作,都是通过脚本自动执行的。
    2、追踪和管理系统的重要工作。例如,我们想重新启动系统注册表文件,可以使用“/etc/init.d/syslogd restart”,syslogd就是script。
    3、简单入侵检测功能。
    4、连续命令的单一化。例如需要执行很多相似的命令,就可以使用script实现。
    5、简单的数据处理。例如使用awk可以对数据进行处理
    6、跨平台支持与学习历程较短。因为几乎所有的UNIX系统都会使用shell script。
    缺点:虽然shell script号称是程序,但是处理数据的速度上是不够的,因为shell script用的是外部命令与bash shell的一些默认工具,所以,它经常会调用外部函数库,因此周期长。
三、Shell 编程语法
    1、变量
       在shell里面,变量通常并不需要事先声明,只是通过使用它们来创建它们。默认情况下,所有变量都被看作字符串并以字符串来存储,即使被赋值为数值时也是如此。在shell中,可通过在变量前面加一个$符号来访问它的内容。增加变量内容,使用“$var”或者${var}
       注:如果字符串里包含空格,就必须用引号把它们括起来。此外,等号两边都不能有空格。因此字符串通常都被放在双引号中,以防止变量被空白符分开,同时允许$拓展。
   (1) 使用引号
       将$变量表达式放在双引号中,程序自动替换引号中变量的值,如果放在单引号 中,不会发生替换现象。
          
   (2)环境变量
       主要的环境变量(自定义变量=局部变量   系统变量=全局变量)

$HOME	           当前用户的家目录
$PATH	           以冒号分隔的用来搜索命令的目录列表
$PS1	           命令提示符,通常是$字符。
$PS2	           二级提示符,用于提示后续的输入,通常是>字符
$IFS	           输入域分隔符。Shell输入时用它来分隔字符,通常是空格、制表符或换行符
$0	               Shell脚本的名称
$#	               传递个脚本的参数个数
$$	               Shell脚本的进程号,通常用它生成唯一的临时文件
?	               上一个任务的回传码
export	           自定义变量转成环境变量
    (3)参数变量
$1,$2…..
脚本程序的参数
$*
在一个变量中列出所有的参数,各个参数之间用IFS分隔开。若IFS被修改,则$*将命令行分隔为参数的方式将随之改变。
$@
$*的变体,不适用IFS
    (4)变量的读取
       变量键盘读取、数组与声明:read、array、declare
       Read:读取来自键盘输入的变量    参数 –p(后面接提示符)  -t(等待时间)
       Array:   echo  “${var[1]}”  “${var[2]}”  
       Declare/typeset:  声明变量的类型
                   
     2、布尔判断命令[或test
      test  -f   file  等价于 [  -f file  ]
      注:使用[]时每个组件之间都需要空格来分隔,中括号里面的变量最好使用“”括起来,常量最好都以‘‘或“”括起来。
      条件类型: 
string 1  = string2     如果两个字符串相同则结果为真
string 1 != string2     如果两个字符串不相等则为真
    -n  string          字符串不为空则为真
    -z  string          字符串为空则
文件条件测试:
-d  file	判断文件名是否存在且为目录
-e  file	判断文件名是否存在
-f  file	判断文件名是否存在且为文件
-g  file	判断文件名是否存在且具有“SGID”的属性
-u  file	判断文件名是否存在且具有“SUID”的属性
-r  file	判断文件名是否存在且具有“可读”的权限
-x  file	判断文件名是否存在且具有“可执行”的权限
-w  file	判断文件名是否存在且具有“可写”的权限
-s  file	判断文件名是否存在且为“非空白文件”
-p  file	判断文件名是否存在且为一个FIFO(pipe)文件
-b  file	判断文件名是否存在且为一个block device设备
-c  file	判断文件名是否存在且为一个character device设备
-L  file	判断文件名是否存在且为一个连接文件
算术比较:

expression1  -eq   expression2	两个表达式相等则为真
expression1  -ne   expression2	两个表达式不相等则为真
expression1  -gt   expression2	expression1大于expression2为真
expression1  -ge   expression2	expression1大于等于 expression2为真
expression1  -lt   expression2	expression1小于 expression2为真
expression1  -le   expression2	expression1小于等于 expression2为真
    !  expression	        表达式为假则结果为真
多重条件判断,例如test  -r filename   -a  -x filename
-a	两个条件同时满足
-o	两个条件满足任意一个
!	反向状态
3、控制结构
   (1)if语句
      格式:
if  condatation                if   condtaion  then
then                               statements
    statements      ======     elif 
elif                               statements
    statements                 else
else                               statements
    statements                 fi
fi
      例:  if  [  -f file  ];  then
   (2)for语句
      格式:    
for  variable in  values
do
    statements
 done
      注:使用通配符可以拓展语句
      例如:循环从1加到100       for  variable in  $ ( seq 1 100 );
   (3)while语句
      格式: 
while  condation do
    statements
done
   (4)until语句
      格式: 
until  condaion
do
    statements
 done 
   (5)case 语句
      格式: 
case  variable in
    pattern  [ |  pattern  ]  …)  statements;;
    pattern  [ |  pattern  ]  …)  statements;;
     …..
esac   
   (6)命令列表
      AND列表:statement1  &&  statements2 &&  statements3  && ….
      OR  列表:statements1  ||   statements2   ||   statements3 ||  … 
   (7)语句块
      在某些只能使用单个语句的地方,可以使用语句块实现多条语句的执行。
    4、函数
       格式:   
function  fname() {
    .....
}
四、命令
    1、break:可以在控制条件未满足之前,跳出for、while或until循环。
    2、””命令:它是一个空命令。偶尔用于简化条件逻辑,相当于true的别名。
               while  true   =====   while  :
    3、continue:这个命令使for、while或until循环跳到下一循环继续执行。
    4、”.” 命令:用于在当前shell中执行命令
      通常,当一个脚本执行一条外部命令或脚本程序时,会启动一个新的shell,命令将在这个新环境中执行,执行完毕之后,环境会被丢弃,留下退出码返回给父shell。  但外部source命令和点命令在执行脚本程序中列出的命令时,使用的是调用该脚本程序的同一个shell。
    5、echo命令:用于输出。
      常见的一个问题是去掉换行符解决方式有:
               echo  -n  “string  to output”
               echo  -e  “string  to  output   \c” 
    6、eval命令:允许对参数求值。
    7、exit  n命令:使脚本程序以退出码n结束运行。    
126                 文件不可执行
127                 命令未找到
128及以上           出现一个信号
    8、export命令:将作为它参数的变量导出到子shell中,并使之在子shell中有效。默认情况下,在一个shell中被创建的变量在这个shell调用的下级(子)shell中是不可用的。Export命令把自己的参数创建为一个环境变量,而这个环境变量可以被当前程序调用的其他脚本和程序看见。从更技术的角度来说,被导出的变量构成从该shell衍生的任何子进程的环境变量。
    9、expr  ==  $((……))   用于算术替换,而$( )用于命令的执行和获取输出。
    10、trap命令:用于指定在接收到信号后将要采取的行动。
        一种常见用途是在脚本程序被中断时完成清理工作。     
trap command   signal     
trap   "rm -f temp_file"   EXIT
    11、find命令:用于搜索文件的命令。
        语法:  find  [path] [options]  [tests]   [actions]       
选项	                含义
-depth	          在查看目录本身之前先搜索目录的内容
-follow	          跟随符合链接
-maxdepths N	  最多搜索N层目录
-mount	          不搜索其他文件系统中的目录
       注:通常使用圆括号来强制测试和操作符的优先级
    12、grep(通用正则表达式解析器  General Regular ExpresiionPraser):在文件中搜索字符串
       语法:  grep  [options] PATTERN  [FILES]                            
options:
-c	输出匹配行的数目,而不是输出匹配的行
-E	启用拓展表达式
-h	取消每个输出行的普通前缀,即匹配查询模式的文件名
-i	忽略大小写
-l	只列出包含匹配行的文件名,而不是输出真正的匹配行
-v	取反操作    
13、 正则表达式,通常配合grep使用
       常见的特殊字符          
^	指向一行的开头
$	指向一行的结尾
.	任意单个字符
[]	方括号内包含一个字符范围,其中任何一个字符都可以被匹配
               特殊匹配模式
[:alnum:]
字符与数字字符
[:alpha:]
字母
[:ascii:]
ASCII字符
[:blank:]
空格或制表符
[:cntrl:]
ASCII控制字符
[:digit:]
数字
[:graph:]
非控制、非空格字符
[:lower:]
小写字母
[:print:]
可打印字符
[:punct:]
标点符号字符
[:space:]
空白符
[:upper:]
大写字符
[:xdigit:]
十六进制数字
 
 
五、Shell script编写
#!/bin/bash

 

#This is a program about CD collection

#Copyright (C) 2014

 

#command line description

#wc命令

 #wc(Word Count)命令的功能为统计指定文件中的字节数、字数、行数

  #并将统计结果显示输出

  #-c统计字节数。

  #-l统计行数

  #-m统计字符数。这个标志不能与-c 标志一起使用

  #-w统计字数

#grep命令

  #通用正则表达式解析器

  #在文件中搜索字符串

 #grep [options] PATTERN [FILES]

 #options

 #-c   输出匹配行的数目

 #-E   启用拓展表达式

 #-h   取消每个输出行的普通前缀

 #-i   忽略大小写

 #-l   只列出包含匹配行的文件名

 #-v   对匹配模式进行取反操作

#cut命令   

 #cut是一个选取命令,就是将一段数据经过分析,取出我们想要的。一般来说,选取信息通常是针对            “行”来进行分析的,并不是整篇信息分析的。

 #cut  [-bn] [file] 或 cut [-c] [file]  或  cut [-df] [file]

 #cut 命令从文件的每一行剪切字节、字符和字段并将这些字节、字符和字段写至标准输出。

  #如果不指定 File 参数,cut 命令将读取标准输入。必须指定 -b、-c 或 -f 标志之一。

  #主要参数

  #-b:以字节为单位进行分割。这些字节位置将忽略多字节字符边界,除非也指定了 -n 标志。

  #-c:以字符为单位进行分割。

  #-d:自定义分隔符,默认为制表符。

 #-f  :与-d一起使用,指定显示哪个区域。

  #-n:取消分割多字节字符。仅和-b 标志一起使用。如果字符的最后一个字节落在由 -b 标志的 List 参数指示的
范围之内,该字符将被写出;否则,该字符将被排除。 #set envrironment variable menu_choice="" current_cd="" title_file="title.cdb" tracks_file="tracks.cdb" temp_file="cdb.$$" trap 'rm -f $temp_file' EXIT get_return(){ echo -e "Press return \c" read x return 0 } get_comfire(){ echo -e "Are you sure? \c" while true do read x case "$x" in y | yes | YES | Yes ) return 0;; n | NO | No | N ) echo "Canclled!" return 1;; * ) echo "Pleasse enter yes or no!" esac done } # Menu set_menu_choice(){ clear echo "Options :-" echo echo " a) Add new CD" echo " f) Find CD" echo " c) Count the CDs andtracks in the catalog" if [ "$cdcatnum" != "" ]; then echo " l) List tracks on$cdtitle" echo " r) Remove$cdtitle" echo " u) Update trackinformation for $cdtitle" fi echo " q) Quit" echo echo -e "Please enter choice then press retrun \c" read menu_choice return } insert_title(){ #insert information to title_file echo $* >> $title_file return } insert_track(){ echo $* >> $tracks_file return } add_record_tracks(){ echo "Enter track information for this CD" echo "When no more tracks enter q" cdtrack=1 #define the title of track cdttitle="" #set $cdttitle = null while [ "$cdttitle" != q ] do #input title echo -e "Track $cdtrack, track title? \c" read tmp cdttitle=${tmp%%,*} if [ "$tmp" != "$cdttitle" ]; then echo "Sorry, no commas allowed" continue fi if [ -n "$cdttitle" ]; then if [ "$cdttitle" != "q" ]; then insert_track $cdcatnum,$cdtrack,$cdttitle fi else cdtrack=$((cdtrack-1)) fi cdtrack=$((cdtrack+1)) done } add_records(){ echo -e "Enter catalog name \c" read tmp cdcatnum=${tmp%%,*} echo -e "Enter title \c" read tmp cdtitle=${tmp%%,*} echo -e "Enter type \c" read tmp cdtrack=${tmp%%,*} echo -e "Enter artist/composer \c" read tmp cdac=${tmp%%,*} #Check that they want to enter the information echo About to add new entry echo "$cdcatnum $cdtitle $cdtype $cdac" #if comfired then append it to the tille_file if get_comfire ; then insert_title $cdcatnum,$cdtitle,$cdtype,$cdac add_record_tracks else remove_records fi return } find_cd(){ if [ "$1" = "n" ]; then asklis=n else asklist=y fi cdcatnum="" echo -e "Enter a string to search for in the CD titles \c" read searchstr if [ "$searchstr" = "" ]; then return 0 fi if [ ! -e $temp_file ]; then echo"temp_file don'texist!!!!!!!!" fi grep "$searchstr" $title_file > $temp_file set $(wc -l $temp_file) linesfound=$1 case "$linesfound" in 0 ) echo "Sorry, nothing found" get_return return 0 ;; 1 ) ;; 2 ) echo "Sorry, not unique." echo "Found the following" cat $temp_file get_return 0 ;; esac IFS="," read cdcatnum cdtitle cdtype cdac < $temp_file IFS=" " if [ -z "$cdcatnum" ]; then echo "Sorry, could not extract catalog filed from $temp_file" get_return return 0 fi echo echo Catalog number: $cdcatnum echo Title: $cdtitle echo Type: $cdtype echo Artist: $cdac echo get_return if [ "$asklist" == "y" ]; then echo -e "View tracks for this CD? \c" read x if [ "$x" == "y" ]; then echo list_tracks echo fi fi return 1 } update_cd(){ if [ -z "$cdcatnum" ]; then echo "You must select a CD" find_cd n fi if [ -n "$cdcatnum" ]; then echo "Current tracks are:-" list_tracks echo echo "this will re-enter the tracks for $cdtitle" get_comfire && { grep -v "^${cdcatnum}," $tracks_file > $temp_file mv $temp_file $tracks_file echo add_record_tracks } fi return } count_cds(){ #wc -l file : statistic thecounts set $(wc -l $title_file) num_titles=$1 set $(wc -l $tracks_file) num_tracks=$1 echo found $num_titles CDs with a total of $num_tracks tracks get_return return } remove_records(){ if [ -z "$cdcatnum" ]; then echo "You must select a CD" find_cd n fi if [ -n "$cdcatnum" ]; then echo "You are about to delete $cdtitle" get_comfire && { grep -v "^${cdcatnum}," $title_file > $temp_file mv $temp_file $title_file grep -v "^${cdcatnum}," $tracks_file > $temp_file mv $temp_file $tracks_file cdcatnum="" echo Entry removed } get_return fi return } list_tracks(){ if [ "$cdcatnum" == "" ]; then echo "No CD selected yet" return else grep -v "^${cdcatnum}," $tracks_file > $temp_file num_tracks=$(wc -l $temp_file) if [ "$num_tracks" = "0" ]; then echo no tracks found for $cdtitle else { echo echo "$cdtitle :-" echo cut -f 2- -d , $temp_file echo } | ${PAGER:-more} fi fi get_return return } #rm -f $temp_file if [ ! -f $title_file ]; then touch $title_file fi if [ ! -f $tracks_file ]; then touch $tracks_file fi if [ ! -f "$temp_file" ]; then touch $temp_file fi #Now the application proper clear echo echo echo "Mini CD manager" sleep 1 quit=n if [ -e $temp_file ]; then echo "temp_file don't exist!!!" return EXIT fi while [ "$quit" != "y"]; do set_menu_choice case "$menu_choice" in a) add_records;; r) remove_records;; f) find_cd y;; c) count_cds;; l) list_tracks;; b) echo more $title_file echo get_return;; q| Q ) quit=y;; *) echo "Sorry, choice not recoginzed";; esac done #Tidy up and leave rm -f $temp_file echo "Finished" exit 0

运行结果
显示主目录

添加CD

添加成功之后返回结果:


查找CD:

删除CD:
 
结束脚本:
 
              

你可能感兴趣的:(C/C++,Linux)