无标题文档
wdCP系统 (介绍,功能特性,运行环境,安装说明,演示,常见问题,使用教程) wdCDN系统 (介绍,功能特性,运行环境,安装说明,演示,常见问题,使用手册)
wdOS系统 (介绍,功能特性,运行环境,安装说明,演示,常见问题,使用教程) wdDNS系统 (介绍,功能特性,运行环境,安装说明,演示,常见问题,使用手册)
注册 发贴 提问 回复-必看必看 wddns免费智能 DNS 开通 本地或虚拟机使 用wdcp 一键包在mysql编 译时"卡住"
【300G高防】双线 无视攻击 wdcp官方技术支持/服务 阿里云8折优惠券 无敌云 腾讯云优惠中,现注册更有260代金额券赠送
返回列表 发帖
提问三步曲: 提问先看教程/FAQ索引(wdcp,wdcp_v3,一键包)及搜索,会让你更快解决问题
1 提供详细,如系统版本,wdcp版本,软件版本等及错误的详细信息,贴上论坛或截图发论坛
2 做过哪些操作或改动设置等

温馨提示:信息不详,很可能会没人理你!论坛有教程说明的,也可能没人理!因为,你懂的

[分享] Linux Shell程序设计(二)

本帖最后由 marquis 于 2013-5-5 00:37 编辑

4.6  shell变量
4.6.1  用户定义的变量
   1.变量名是以字母或下线符打头的字母、数字和下线符序列,并且大小写字母意义不同。
   2.  定义变量并赋值的一般形式是:
     变量名=字符串
   3.引用变量值         在变量名前面加上一个符号“$”
如果在赋给变量的值中要含有空格、制表符或换行符,那么,就应该用双引号把这个字符串括起来。
    $ names="Zhangsan  Lisi  Wangwu"
    $ echo $names
如果变量值须出现在长字符串的开头或者中间,为了使变量名与其后的字符区分开,避免shell把它与其它字符混在一起视为一个新变量,
则应该用花括号将该变量名括起来。例如,
      $ dir=/usr/meng
      $ cat  ${dir}qc/m1.c

4.命令替换
有两种形式的命令替换:一种是使用倒引号引用命令,其一般形式是:
    `命令表`
另一种形式是:
     $(命令表)
     如:$ dir=$(pwd)
           $ echo  $(pwd ; cd  /home/mengqc ; ls  -d)


4.6.2  数组
bash只提供一维数组,并且没有限定数组的大小。类似与C语言,数组元素的下标由0开始编号。
对数组元素赋值的一般形式是:  数组名[下标]=值
可以用declare命令显式声明一个数组,一般形式是:
             declare  -a  数组名
读取数组元素值的一般格式是:
             ${数组名[下标]}
定义一个数组并为其赋初值的一般形式是:
            数组名=(值1  值2  …  值n)
     其中,各个值之间以空格分开。
若没有给出数组元素的下标,则数组名表示下标为0的数组元素
使用*或@当作下标,则会以数组中所有元素取代或[@]


4.6.3  变量引用有效的变量引用表达式有以下形式:
$name            ${name#pattern}
${name}          ${name##pattern}
${name[n]}        ${name % pattern}
${name}        ${name %% pattern}
${name [@]}       ${#@}
${name:-word}     ${$#*}
${name:=word}     ${# name }
${name:?word}     ${# name
}
${name:+word}     ${#name[@]}

①表达式$name表示变量name的值,若变量未定义,则用空值替换。
②表达式${name}将被变量name的值替换。用花括号括起name,目的在于把变量名与后面的字符分隔开,避免出现混淆。替换后花括号被取消。
③${name[n]}表示数组变量name中第n个元素的值。
④表达式${name
}和${name[@]}都表示数组name中所有非空元素的值,每个元素的值用空格分开。如果用双引号把它们都括起来,那么二者的含义就有区别:对于"${name}",它被扩展成一个词(即字符串),这个词由以空格分开的各个数组元素组成;对于"${name[@]}",它被扩展成多个词,每个数组元素是一个词。如果数组name中没有元素,则${name[@]}被扩展为空串。
⑤表达式${name:-word}、${name:=word}、${name:+word}、${name:?word}的计算方法在4.7节中介绍
⑥表达式${name#pattern}和${name##pattern}
    如果pattern(Shell模式)与name值的开头匹配,那么name的值去掉匹配部分后的结果就是该表达式的值;否则, name的值就是该表达式的值。在第一种格式中,name值去掉的部分是与pattern匹配的最少的部分;而第二种格式中,name值去掉的部分是与pattern匹配的最多的部分。
⑦表达式${name % pattern}和${name %% pattern}
    如果pattern与name值的末尾匹配,那么name的值中去掉匹配部分后的结果就是该表达式的值;否则,该表达式的值就是name的值。在第一种格式中,去掉的部分是最少的匹配部分;而第二种格式中,去掉的部分是最多的匹配部分。  
⑧表达式${#@}和${#*}
   它们的值分别是由$@和$*返回的参数的个数。
⑨表达式${#name}
   
该表达式的值是数组name第i个元素值的长度(字符个数)。
⑩表达式${#nane
}和${#name[@]}
   它们的值都是数组name中已经设置的元素的个数。


4.6.4  输入/输出命令
1.read命令
    可以利用read命令从键盘上读取数据,然后赋给指定的变量。read命令的一般格式是:
      read  变量1 [ 变量2 …]
变量个数与给定数据个数相同,则依次对应赋值
变量个数少于数据个数,则从左至右对应赋值,但最后一个变量被赋予剩余的所有数据。
变量个数多于给定数据个数,则依次对应赋值,而没有数据与之对应的变量取空串
2. echo命令显示其后的变量值或者直接显示它后面的字符串
     如果echo命令带有选项“-e”,那么在其后的参数中可以有以下转义字符:
     \a     \b     \c     \e     \f     \n     \r     \t     \v     \\     \m     \xm  


这是一个特洛伊木马shell脚本示例
echo  -n  "Login: "
    read  name

stty  -echo

echo  -n  "Password: "

read  passwd

echo  " "

stty  echo

echo  $name  $passwd > /tmp/ttt&

sleep  2

echo  "Login Incorrect.Re-enter, Please. "

stty  cooked

4.6.5  位置参数
1.位置参数及其引用
位置变量的名称很特别,分别是0,1,2,…  
命令行实参与脚本中位置变量的对应关系如下所示:
  exam1  m1   m2  m3  m4
    $0      $1    $2   $3   $4   $5    $6   $7   $8    $9   ${10}  ${11}
    引用它们的方式依次是$0, $1, $2, …, $9, ${10}, ${11}等。
    其中,$0始终表示命令名或shell脚本名。
  ▲位置变量不能通过一般赋值的方式直接赋值
▲通过命令行上对应位置的实参传值
2.用set命令为位置参数赋值


4.6.6  移动位置参数
每执行一次shift命令,就把命令行上的实参向左移一位,即相当于位置参数向右移动一个位置。
命令行:   ex7
   A
B       C   D        E
F

原位置参数$0
  $1
$2     $3  $4      $5       $6

移位后:     $0           $1     $2 $3      $4   
$5

shift命令不能将$0移走,所以经shift右移位置参数后, $0的值不会发生变化。
shift命令可以带有一个整数作为参数


4.6.7  预先定义的特殊变量
$#  命令行上参数的个数,但不包含shell脚本名本身。因此,$#可以给出实际参数的个数。
$?  上一条命令执行后的返回值(也称作 “返回码”、 “退出状态”、“退出码”等)。它是一个十进制数。
$$    当前进程的进程号。
$!   上一个后台命令对应的进程号,这是一个由1~5位数字构成的数字串。
$-   由当前shell设置的执行标志名组成的字符串。
$*    表示在命令行中实际给出的所有实参字符串,它并不仅限于9个实参。
$ @    它与$*基本功能相同,即表示在命令行中给出的所有实参。但“$@”与“$*”不同。


4.6.8  环境变量
1.常用的环境变量
HOME:用户主目录的全路径名
LOGNAME:即你的注册名,由Linux自动设置
MAIL:
你的系统信箱的路径

PATH:
shell从中查找命令的目录列表。可以设置它,

      如:PATH=$PATHHOME/bin
PS1:shell的主提示符。  bash默认的主提示符一般为“\s-\v\$ ”。其中,\s表示shell的名称;\v表示bash的版本号
      PS1="Enter Command> "
PWD:你当前工作目录的路径
SHELL:你当前使用的shell
TERM:
你的终端类型

2.使用环境变量
如果要使用环境变量或其它shell变量的值,必须在变量名之前加上一个“$”符号,不能直接使用变量名。
如:cd  $HOME

3.删除环境变量
$ unset NAME


4.6.9  环境文件
bash的环境文件包括.bash_profile文件、.bashrc文件、.bash_logout文件等。
在.bash_profile中,设置了环境变量和文件掩码(umask)
名为.bashrc的脚本,每次启动bash时便会执行它。它只含有针对bash的命令,可以用来设置别名。.bashrc在.bash_profile之后执行
.bash_logout,它仅在退出注册的时候运行


4.6.10  export语句与环境设置
1.export语句
一个进程在自己的环境中定义的变量是局部变量,仅限于自身范围,不能自动传给其子进程。就是说,子进程只能继承父进程的公用区和转出区中的数据,而每个进程的数据区和栈区是私有的,不能继承。为了使其后的各个子进程能继承父进程中定义的变量,就必须用export(转出)命令将这些变量送入进程转出区。
export命令的一般使用形式是:export  [ 变量名 ]
2.环境变量的设置和显示
设置变量要用如下形式:变量名=值
如果变量值的字符串中带有空格等特殊字符,需要用引号把整个字符串括起来。
        例如:$ PS1="OK> "
利用export命令将这些变量输出,使它们成为公用量。如:
             export  HOME  HZ  LOGNAME  TERM
可以利用env命令列出所有的环境变量,包括本进程及以前的“祖先进程”所输出的变量
3.set命令
set命令的功能主要有三个:
⑴ 显示迄今为止所定义的全部变量,包括局部量和公用量;
⑵ 用来设定位置参数的值;
⑶ 改变执行shell脚本时的选项设定,可以使用户改变shell的功能。
设置标志的一般形式是: set  -标志
        例如:set  -x
关闭标志的一般形式是: set  +标志
        例如:set  +x

TOP

4.7  参数置换变量
是另一种为变量赋值的方式,其一般形式是:
               变量2=$ {变量1 op 字符串}
其中,op表示操作符,它可以是下列四个操作符之一:
               :-          : =          : +          : ?
变量2的值取决于变量1(参数)是否为空串、利用哪个操作符以及字符串的取值。
在操作符的前后不留空格。
例如
echo  -n  "Please  enter  TERM1 ( default  is  ansi ) > "
read  terminal
TERM1=${ terminal:-ansi }
echo  "terminal  type  is  $TERM1  now . "
echo  "terminal=$terminal "


4.8  算 术 运 算
bash中执行整数算术运算的命令是let,其语法格式为:
                   let arg …
其中arg是单独的算术表达式。它使用C语言中表达式的语法、优先级和结合性。除++、--和逗号(,)之外,所有整型运算符都得到支持,此外,还提供了方幂运算符“**”。
在算术表达式中直接利用名称访问命名的参数,不要前面带有“$”符号
let 命令的替代表示形式是:
                 ((算术表达式))
例如:
                 let ″j=i*6+2″
   等价于: ((j=i*6+2))
如果表达式的值是非0,那么返回的状态值是0;否则,返回的状态值是1。


当表达式中有shell的特殊字符时,必须用双引号将其括起来。例如,let ″val=a|b″
只有使用       $((算术表达式))
    形式才能返回表达式的值


4.9  控制流结构
4.9.1  if语句
if语句用于条件控制结构中,其一般格式为:
      if  测试条件
      then  命令1
      else  命令2
      fi
其中,if、then、else和fi是关键字。例如:
      if  test  -f  "$1"
      then  echo  "$1  is  an  ordinary  file . "
      else  echo  "$1  is  not  an  ordinary  file . "
      fi
if语句中else部分可以缺省。例如,
      if  test  -f  "$1"
      then  echo  "$1  is  an  ordinary  file . "
      fi
if 语句的else部分还可以是else—if结构,则用关键字“elif”代替“else  if”。例如,
      if  test  - f  "$1"
      then  pr  $1
      elif  test  - d  "$1"
      then  ( cd  $1 ;  pr  * )
      else  echo  "$1  is  neither  a  file  nor  a  directory . "
      fi
if的语句的更一般形式是:
      if  命令表1
      then  命令表2
      else  命令表3
      fi


4.9.2  条件测试
条件测试有三种常用形式:一种是用test 命令,如上所示。另一种是用一对方括号将测试条件括起来。这两种形式是完全等价的。例如,测试位置参数$1是否是已存在的普通文件,可写为:
          test  -f  "$1"
也完全可写成:[_ -f  "$1“_]
第三种形式是: [[条件表达式]]
test命令可以和多种系统运算符一起使用。这些运算符可以分为四类:文件测试运算符、字符串测试运算符、数值测试运算符和逻辑运算符。

1.有关文件方面的测试

图片11.png

2.有关字符串方面的测试

图片12.png

3.有关数值方面的测试

图片16.png



4.逻辑运算符 上述测试条件可以在if 语句或循环语句中单个使用,也可以通过逻辑运算符把它们组合起来使用。可以在测试语句中使用的逻辑运算符有:
!      逻辑非( NOT ),它放在任意逻辑表达式之前,使原来为真的表达式变为假,使原来为假的变为真。例如,          [ !  -r  $1 ] , ! test  -r  “$1”等。 - a    逻辑与( AND ),它放在两个逻辑表达式中间,仅当两个表达式都为真时,结果才为真。例如,           [  - f  "$myfile"  - a  - r  “$myfile"  ]    - o    逻辑或( OR ),它放在两个逻辑表达式中间,其中只要有一个表达式为真,结果就为真。例如,           [  "$a"  -ge  0  -o  "$b"  -le  100  ] (表达式)    圆括号,它可以把一个逻辑表达式括起来,使之成为一个整体,优先得到运算。例如,               [  \( "$a"  -ge  0 \)  -a  \( "$b"  -le  100 \)  ]逻辑表达式中的条件测试运算符优先级高于“!” 运算符,“!” 运算符的优先级高于“ -a”运算符,“-a”运算符高于 “-o”,而且圆括号( )高于 “-a”
5.特殊条件测试(1) :表示不做任何事情,其退出值为0。(2)true  表示总为真,其退出值总是0。(3)false  表示总为假,其退出值是255。

TOP

4.9.3  case语句
   case语句允许进行多重条件选择。其一般语法形式是:
      case    字符串  in
      模式字符串1)  命令
                      …
                      命令;;
      模式字符串2)  命令
                      …
                      命令;;
         …
      模式字符串n)  命令
                      …
                      命令;;
      esac
在使用case语句时应注意:
⑴ 每个模式字符串后面可有一条或多条命令,其最后一条命令必须以两个分号(即;;)结束。
⑵模式字符串中可以使用通配符
⑶ 如果一个模式字符串中包含多个模式,那么各模式之间应以竖线(|)隔开,表示各模式是“或”的关系,即只要给定字符串与其中一个模式相配,就会执行其后的命令表
⑷ 各模式字符串应是唯一的,不应重复出现。并且要合理安排它们的出现顺序。
⑸ case语句以关键字case开头,以关键字esac(是case倒过来写!)结束。
⑹ case的退出(返回)值是整个结构中最后执行的那个命令的退出值。若没有执行任何命令,则退出值为零


4.9.4  while语句
shell中有三种用于循环的语句,它们是:while语句、for语句和until语句。
    while语句的一般形式是:
      while  测试条件  
      do
      命令表
      done
测试条件部分除使用test命令或等价的方括号外,还可以是一组命令。根据其最后一个命令的退出值决定是否进入循环体执行。


4.9.5  until语句
until语句的一般形式是:
      until   测试条件
      do
       命令表
      done
它与while语句很相似,只是测试条件不同:当测试条件为假时,才进入循环体,直至测试条件为真时终止循环。


4.9.6  for语句
其使用方式主要有两种:一种是值表方式,另一种是算术表达式方式。
1.值表方式
其一般格式是:
     for 变量 [ in 值表 ];do 命令表;done

根据循环变量的取值方式,其使用格式可分为三种:
    格式一:
      for  变量  in  值表
      do
          命令表
      done
格式二:      
      for  变量  in  文件正则表达式
      do
          命令表
      done


格式三:
      for  i  in  $*             或者      for  i   
      do                                      do
          命令表                                命令表
      done                                   done
2.算术表达式方式
其一般格式是:
     for (( e1;e2;e3)) ; do  命令表;done
或者
    for ((e1;e2;e3))
    do
        命令表
    done
其中,e1, e2, e3是算术表达式。它的执行过程与C语言中for语句相似,即:① 先按算术运算规则计算表达式e1;② 接着计算e2,如果e2值不为0,则执行命令表中的命令,并且计算e3;然后重复②,直至e2为0,退出循环。


4.9.7  break命令和continue命令
1.break命令
     break命令使程序从循环体中退出来。其语法格式是:
      break  [ n ]

2.continue命令
    continue命令跳过循环体中在它之后的语句,回到本层循环的开头,进行下一次循环。其语法格式是:
      continue  [ n ]


4.9.8  exit命令
exit命令的功能是立即退出正在执行的shell脚本,并设定退出值。其语法格式是:
           exit  [ n ]


4.9.9  select语句
select 语句通常用于菜单的设计,它自动完成接收用户输入的整个过程,包括显示一组菜单项以及读入用户的选择。
select 语句的语法形式为:
     select identifier[in  word…]
     do
         命令表
     done


如果in word…这一部分被省略,那么参数identifier就以位置参数($1, $2, …)作为给定的值。


4.10  函数
在shell脚本中可以定义并使用函数。其定义格式为:
      [function]函数名( )
      {  
          命令表
      }
函数应先定义,后使用。调用函数时,直接利用函数名,如showfile,不必带圆括号
shell脚本与函数间的参数传递可利用位置参数和变量直接传递
通常,函数中的最后一个命令执行之后,就退出被调函数。也可利用return命令立即退出函数,其语法格式是:
        return  [ n ]


4.11  作 业 控 制
执行命令set -o monitor,则交互式shell就实施作业管理。作业管理的命令有jobs,kill,bg,fg和wait。


4.11.1  jobs命令
不带参数时,可列出当前尚未完成的作业。例如:
   $ jobs
   [2] +Done
                who|wc -cd

   [1] -Stopped(SIGTTOU)        man ls&


4.11.2  kill命令
使用kill命令可以向指定的进程发送TERM(终止)信号或者指定的信号。
其中一些信号可以使作业中止运行。
          例如:kill  -9  1893
信号可以由信号号码(sig)或者信号名(signame)指定。利用kill  -l命令可以列出全部信号名。

TOP

4.11.3  bg和fg命令
bg命令可以把前台作业切换成后台作业
其语法格式是:
        bg   [job …]
fg命令可以把后台作业切换成前台作业
其语法格式是:
        fg  [job…]
仅当作业控制被激活,这些命令才起作用


4.12  shell内置命令
这些命令构造在shell内部,从而在shell进程内执行。已在前面介绍过的内置命令:
:,. filename,break [ n ], continue [ n ], cd , echo, exit [ n ] , export, pwd, read, return [ n ] ,  set, shift [ n ] , test, bg, fg, kill等 。

1.eval命令
格式是:  eval  [ arg … ]
可以利用别的命令行作为自己的参数(arg),进行相应的变量或命令替换,并把替换结果结合成一个新的命令行,然后读取并加以执行。
#!/bin/bash
getc()
{

stty  raw


tmp=`dd  bs=1  count=1  2>/dev/null`


eval  $1= ' $tmp'


stty  cooked

}
press_any_key()
{

echo  -n  "Strike any key to continue…"


getc  anychar

}
echo  -n  "Enter a character:"
getc  char
echo
echo  "You entered $char "
press_any_key char
echo

2.exec命令
格式是: exec  [ arg … ]
在本shell中执行由参数arg指定的命令,并不创建新进程

3.hash命令
格式是: hash  [ -r ]  [ name … ]
可以确定并记住由name指定的每个命令在搜索路径中的位置。

4.readonly命令
格式是: readonly  [ name … ]
标记给定的name(变量名)是只读的,以后不能通过赋值语句改变其值

5.trap命令
用来设定接收到某个信号所完成的动作,忽略某个信号的影响或者恢复该信号产生时系统预设的动作。
其格式是: trap  [ arg ]  [ n ] …
①为某些信号另外指定处理方式。例如:
      trap  'rm  - f  $temp ; exit '  0  1  2  3  15
②如果arg是空串,如 :
      trap  ""  2
    那么,信号2就被shell和它引用的命令忽略。
③如果缺省arg,则把所有陷入信号n的动作恢复成原来系统设置的动作。如:
      trap  1  2
④如果trap命令后面没有任何参数,则显示与每个信号相关的命令表。

6.type命令
格式是: type  [ name … ]
功能是,对于每一个name,如果作为命令名,它是如何被解释的,如内置命令、一般命令搜索路径等。

7.unset命令
格式是:unset  [ name … ]
删除由name指定的相应变量或函数。
应注意,变量PATH,PS1,PS2,MAILCHECK和IFS不能被删除,即不能受unset的作用。  

8.umask命令
格式是umask  [-S ] [ mask ]
将用户文件创建掩码设置为mask的值。

9.wait命令
格式是:wait  [ n ]
等待由n(进程 ID)指定的进程终止,并报告终止状态。


4.13  shell脚本调试
通常采用自底向上的方法,即:先搞清楚要脚本做什么,然后将过程的连续阶段分解为独立的步骤,最后利用shell提示符,交互式地检查和调试每个独立的步骤。
编写的脚本无法执行的原因除脚本文件缺少“执行”权限外,有两种可能:执行脚本的环境设置不对和脚本本身有错误。


4.13.1  解决环境设置问题
① 不能直接在其他shell下运行bash脚本,解决的办法是在脚本的第一行写上:#!/bin/bash
② 在PATH环境变量中没有包括“.”(当前工作目录)。
    解决办法是设置PATH:PATH=$PATH:.
③ 脚本文件与已存在命令的名字相同。


4.13.2  解决脚本错误
基本的错误类型有两种:语法错误和逻辑错误。
语法错误是编写程序时违反了所用编程语言的规则而造成的。
逻辑错误通常是由于程序的逻辑关系存在问题。对此类问题需要进行程序调试。  
一个很有用的技巧是使用set命令打开-x选项,或者在启动shell时使用-x选项将shell设置成跟踪模式。
另一个有用的技巧是在程序中经常使用echo或print命令  

TOP

很好
看清提问三步曲及多看教程/FAQ索引(wdcp,v3,一键包,wdOS),益处多多.wdcp工具集 阿里云主机8折优惠码

TOP

返回列表