Shell 编程 0 – 基本语法

1.1 shell提示符及其环境

环境:Linux,Unix,Dos等等

Shell是一个解释执行命令的程序,所谓shell编程其实就是用一定的语法将各种基本的命令组合起来,让shell程序去解释执行。

同传统的编程语言一样,shell提供了很多特性,这些特性可以使你的shell script编程更为有用,如:数据变量、参数传递、判断、流程控制、数据输入和输出,子程序及以中断处理等。

1.2 如何执行shell程序

Shell程序后缀名: .sh,如 first.sh

执行shell三种方法:

1(1) bash  first.sh## 1.
2
3(2) 
4chmod u+x first.sh
5./first.sh
6
7(3) . first.sh

1.3 常量

字符串,例如“Hello World!”。

数字,例如755,23。

1.4 变量

shell中变量默认没有类型,简称弱类型,类似于PHP、Javascript、Swift中的变量,无类型声明

1STR="Hello World!"  #定义变量 STR 
2echo $STR         # $ 符号是获得变量STR的值
3
4HOME="/home"
5a=123
6HOME_LIST=$( ls /home ) #把命令的执行结果赋值给变量
7ehco $HOME 
8let a=a+1 #计算

注意:赋值时等号两边不能有空格

系统变量:

系统变量 含义
$0 Shell 脚本 的名字
$n Shell 脚本 的第n个参数值,n=1..9
$* Shell 脚本 的所有参数,此选项参数可超过9个。
$# Shell 脚本 的参数个数
$$ Shell 脚本 的PID(脚本运行的当前进程ID号)
$! 执行上一个背景指令的PID(后台运行的最后一个进程的进程ID号)
$? 执行上一个指令的返回值 (显示最后命令的退出状态。0表示没有错误,其他任何值表明有错误)
$- 显示shell使用的当前选项,与set命令功能相同
$@ 跟$*类似,但是可以当作数组用

1.5 局部变量

局部变量一般是指写在函数中的变量

1.6 从键盘输入变量值

使用read命令

语法:read [-p 输出] 变量名

1read -p "input vars:"  var1 var2 … varn

1.7 注释**

Shell编程中的注释以 # 开头

1.8 数字运算**

主要是指整数运算。expr 命令可以将字符型变量转换为整数进行操作

语法:expr integer operator integer

其中operator为+ - * / %, 但对*的使用要用转义符/,如:

1#!/bin/bash
2
3expr 5 /* 5

Bash shell 的算术运算有四种方式:

1 使用 expr 外部程式

加法 r=`expr 4 + 5` 注意 '4' '+' '5' 这三者之间要有空格
乘法 r=`expr 4 * 5` 注意 * 号要转义

2 使用 $(( ))

1r=$(( 4 + 5 ))

3 使用 $[ ]

 1r=$[ 4 + 5 ]
 2
 3乘法  
 4r=\`expr 4 \* 5\`
 5r=$(( 4 * 5 ))  
 6r=$[ 4 * 5 ]
 7
 8除法  
 9r=\`expr 40 / 5\` <wbr />  
10r=$(( 40 / 5 ))  
11r=$[ 40 / 5 ]
12
13减法  
14r=\`expr 40 - 5\` <wbr />  
15r=$(( 40 - 5 ))  
16r=$[ 40 - 5 ]
17
18求余数  
19r=$[ 100 % 43 ]
20
21乘幂 (23 次方)  
22r=$(( 2 ** 3 ))  
23r=$[ 2 ** 3 ]  
24注:expr 沒有乘幂

4 使用let 命令

 1加法:  
 2n=10  
 3let n=n+1  
 4echo $n #n=11
 5
 6乘法:  
 7let m=n*10
 8
 9除法:  
10let r=m/10  
11求余数:  
12let r=m%7  
13乘冪:  
14let r=m**2

虽然Bash shell 有四种算术运算方法,但并不是每一种都是跨平台的,建议使用expr。
另外,我们在 script 中经常有加1操作,以下四法皆可:

1m=$[ m + 1]  
2m=\`expr $m + 1\`  
3m=$(($m + 1))  
4let m=m+1

PS:shell的内部算术运算符无法处理浮点数,所以当需要处理浮点数是,要用到外部工具(如awk)

1.9 逻辑运算

test进行逻辑运算,与 [ ] 等价, (中括号两边要有空格), 如:[ expression ]

1test int1 -eq int2       #相等? 等价于: [ int1 -eq int2 ]
2test int1 -ne int2       #不等?
3test int1 -gt int2       #int1 > int2 ?
4test int1 -ge int2       #int1 >= int2 ?
5test int1 -lt int2       #int1 < int2 ?
6test int1 -le int2       #int1 <= int2

1.10 双引号及单引号

1echo "$HOME $PATH"  #显示变量值
2/home/hbwork opt/kde/bin:/usr/local/bin:
3
4echo '$HOME $PATH'  #显示单引号里的内容
5$HOME $PATH

1.11 空格

由于shell对命令中的多余的空格不作任何处理 ,而用引号括起来则可以防止shell去掉这些空格。

1$ str1=abcd
2$ str2="abcd      "

1.12 分支结构

1.12.1 结构一

1if [ variable = value ]; then
2  command
3else
4if [ variable = value ]; then
5  command
6else
7  command
8fi

1.12.2 结构二

 1if [ variable = value ]; then
 2  command
 3elif [ variable = value ]; then
 4  command
 5fi
 6
 7# if 语句示例:
 8
 9if [ "22" -lt "33" ]; then   #注意空格
10  echo "22 less than 33"
11else
12  echo "no"
13fi #if语句的结束

1.13 Case语句

 1case value in
 2pattern1)
 3  command
 4;;
 5pattern2)
 6  command
 7;;
 8...
 9
10patternn)
11  command;
12esac
13
14#case 示例:
15
16read -p "enter a number" ans  #读取一个变量read
17case $ans in
181)
19  echo   "you numer is $ans"
20;;                                #注意符号是两个 ;
212)
22  echo "you number is 2"
23;;
24[3-9])
25  echo "you number is $ans"
26;;
27\*)                                
28  echo "others"
29esac

1.14 And 和 Or

command1 && command2 #and关系

command1 || command2 #or关系

1.15 循环语句

1.15.1 For循环

 1for var in arg1 arg2 ... argn; do
 2  command
 3  ....
 4  command
 5done
 6
 7#For循环示例
 8
 9int=1
10for $int in 1 2 3 4 5; do
11  sq=\`expr $int /* $int\`
12  echo $sq
13  int=\`expr $int + 1\`
14done

1.15.2 while循环

 1while command; do
 2  command
 3  command
 4  command
 5  ...
 6done
 7
 8#While循环的示例
 9
10int=1
11while [ $int -le 5 ];do
12  sq=\`expr $int /* $int\`
13  echo $sq
14  int=\`expr $int + 1\`
15done

1.15.3 until循环结构

 1until command; do
 2  command
 3  command
 4  ....
 5  command
 6done
 7
 8#Until循环示例
 9
10int=1
11until [ $int -gt 5 ]; do
12  sq=\`expr $int /* $int\`
13  echo $sq
14  int=\`expr $int + 1\`
15done

1.16 从循环中退出: break和continue命令

break 立即退出循环

continue 忽略本循环中的其他命令,继续下一下循环

1.17 函数 (子过程)

1[ function ] funname [()]
2{
3  command;
4  [return int;]
5}

1、函数可以带 function fun() 定义,也可以直接fun() 定义,不带任何参数。
2、函数参数返回,可以显示加:return 返回,如果不加,将以最后一条命令运行结果,作为返回值。
return后跟数值n(0-255
3、必须在调用函数地方之前,声明函数,shell脚本是逐行运行。不会像其它语言一样先预编译。因此必须在使用函数前先声明函数。
4、returnvalue=$(funname 3 2); 在shell 中 单括号里面是命令语句。 因此,可以将shell中函数看作是定义一个新的命令,因此各个输入参数直接用空格分隔。 命令里面获得参数方法可以通过:$0…$n得到。 $0代表函数本身。
5、函数返回值,只能通过$? 系统变量获得,直接通过 = 获得是空值。其实,函数是一个命令,在shell获得命令返回值,都需要通过$?获得。
6、如果需要传出其它类型函数值,可以在函数调用之前,定义变量(这个就是全局变量)。在函数内部可以直接修改,然后在执行函数就可以读出修改过的值。
7、如果需要定义自己变量,可以在函数中定义:local 变量=值 ,这时变量就是内部变量,它的修改,不会影响函数外部相同变量的值 。

1.18  shell程序的调试

使用-x进行跟踪执行,执行并显示每一条指令。

1.19 比较运算符

1.19.1 文件比较运算符

运算符 含义 示例
-e filename 如果 filename 存在,则为真 [ -e /var/log/syslog ]
-d filename 如果 filename 为目录,则为真  [ -d /tmp/mydir ]
-f filename  如果 filename 为常规文件,则为真 [ -f /usr/bin/grep ]
-L filename 如果 filename 为符号链接,则为真 [ -L /usr/bin/grep ]
-r filename 如果 filename 可读,则为真 [ -r /var/log/syslog ]
-w filename 如果 filename 可写,则为真  [ -w /var/mytmp.txt ]
-x filename 如果 filename 可执行,则为真  [ -L /usr/bin/grep ]
-b filename 如果 filename 块文件,则为真
-c filename 如果 filename 字符文件,则为真
-p filename 如果 filename 管道,则为真
-s filename 如果 filename 大于0,则为真
filename1 -nt filename2 如果 filename1 比 filename2 新,则为真
filename1 -ot filename2 如果 filename1 比 filename2 旧,则为真

 

1.19.2 字符串比较运算符 (请注意引号的使用,这是防止空格扰乱代码的好方法)

运算符 含义 示例
-z string 如果 string 长度为零,则为真 [ -z "$myvar" ]
-n string 如果 string 长度非零,则为真 [ -n "$myvar" ]
string1 = string2 如果 string1 与 string2 相同,则为真 [ "$myvar" = "one two three" ]
string1 != string2 如果 string1 与 string2 不同,则为真 [ "$myvar" != "one two three" ]
string1 < string2 String1 的ASCII在string2前

 

1.19.3 算术比较运算符

运算符 含义
num1 -eq num2 等于
num1 -ne num2 不等于
num1 -lt num2 小于
num1 -le num2 小于或等于
num1 -gt num2 大于
num1 -ge num2 大于或等于

1.20 正则表达式

正则表达式(regular expression)描述了一种字符串匹配的模式,可以用来检查一个串是否含有某种子串、将匹配的子串做替换或者从某个串中取出符合某个条件的子串等。

grep, expr, sed , awk. 或Vi中经常会使用到正则表达式,为了充分发挥 shell 编程的威力,需要精通正则表达式。

如:使用shell时,从一个文件中抽取多于一个字符串将会很麻烦。例如,在一个文本中抽取一个词,它的头两个字符是大写的,后面紧跟四个数字。如果不使用某种正则表达式,在shell中将不能实现这个操作。

一个正则表达式包含下面一个或多个项:

1.一个字符集

这里的字符集里的字符表示的就是它们字面上的意思.正则表达式最简单的情况就是仅仅由字符集组成,而没有其他的元字符。

2.锚

一个锚指明了正则表达式在一行文本中要匹配的位置,例如^和$就是锚。

3.修饰符

它们用于展开或缩小(即是修改了)正则表达式匹配文本行的范围.修饰符包括了星号、括号和反斜杠符号。

运算符 含义
* 匹配重复零次或多次前一字符
+ 匹配一个或多个前面的字符.它的作用和*很相似,但唯一的区别是它不匹配零个字 符的情况
? 匹配零或一个前面的字符。它一般用于匹配单个字符
. 匹配任意字符( 除换行符 )
^ 匹配一行的开头,但依赖于上下文环境,可能在正则表达式中表示否定一个字符 集的意思
[...] 匹配集合中任意字符 如"[xyz]" 匹配字符 x, y, 或z
[^...] 匹配不属集合 中 任意字符
^, $ 匹配 行首、行尾
<, > 用于表示单词的边界。< 匹配词首,>词尾,如"<the>" 匹配单词"the"
... 正则表达式分组。进行子字符串提取(substring extraction)一起使用很有用
\n 第 n 个分组内容
\ 转义(escapes) 一个特殊的字符,使这个字符表示原来字面上的意思。"$"表示 了原来的字面意思"$",而不是在正则表达式中表达的匹配行尾的意思."\"也被 解释成了字面上的意思""
{ } 指示前面正则表达式匹配的次数.要转义是因为不转义的话大括号只是表示他们字面上的意思.这个用法只是技巧上 的而不是基本正则表达式的内容."[0-9]{5}" 精确匹配5个数字(从0到9的数字).
"或" 正则操作符用于匹配一组可选的字符
{n} n是一个非负整数。匹配确定的n次。例如,''o{2}'' 不能匹配 "Bob"中的''o'',但是能匹配"food" 中的两个o。
{n,} n是一个非负整数。至少匹配n次。例如,''o{2,}'' 不能匹配"Bob"中的'o'',但能匹配 "foooood"中的所有o。''o{1,}''等价于''o+''。''o{0,}''则等价于''o*''。
{n,m} m和n均为非负整数,其中n<=m。最少匹配n次且最多匹配m次。例如,"o{1,3}"将匹配 "fooooood"中的前三个o。''o{0,1}''等价于''o?''。请注意在逗号和两个数之间不能有空格。
\b 匹配一个单词边界,也就是指单词和空格间的位置。例如,''er\b'' 可以匹配"never" 中的''er'',但不能匹配 "verb"中的 ''er''。
\B 匹配非单词边界。''er\B''能匹配"verb"中的''er'',但不能匹配"never"中的 ''er''
\w 匹配包括下划线的任何单词字符。等价于''[A-Za-z0-9_]''。
\W 匹配任何非单词字符。等价于''[^A-Za-z0-9_]''。
\d 匹配一个数字字符。等价于[0-9]。
\D 匹配一个非数字字符。等价于[^0-9]。
\f 匹配一个换页符。等价于\x0c和\cL。
\n 匹配一个换行符。等价于\x0a和\cJ。
\r 匹配一个回车符。等价于\x0d和\cM。
\s 匹配任何空白字符,包括空格、制表符、换页符等等。等价于[\f\n\r
\S 匹配任何非空白字符。等价于[^\f\n\r\t\v]。
\t 匹配一个制表符。等价于\x09 和 \cI。
\v 匹配一个垂直制表符。等价于\x0b和\cK。

例子:

 1/\b([a-z]+)\1\b/gi                            #一个单词连续出现的位置
 2
 3/(\w+):\/\/([^/:]+)(:\d\*)?([^# ]\*)/         #将一个URL解析为协议、域、端口及相对路径
 4
 5/^(?:Chapter|Section) \[1-9\]\[0-9\]{0,1}$/   #定位章节的位置
 6
 7/[-a-z]/          #A至z共26个字母再加一个-号。
 8
 9/ter\b/           #可匹配chapter,而不能terminal
10
11/\Bapt/           #可匹配chapter,而不能aptitude
12
13/Windows(?=95 |98 |NT )/   #可匹配Windows95或Windows98或WindowsNT,当找到一个匹配后,从Windows后面开始进行下一次的检索匹配。
14
15#高阶例子:
16
17#vi 中使用:
18
19s/.∗$\n^.*$/\1/g      #将两行(如行1和行2 )内容替换为第一行内容(即行1的内容)
20
21%s/.∗$\n^.*$/\1/g     #删除偶数行
22
23%s/^.*$\n.∗$/\1/g     #删除奇数行
24
25#其它:
26
27sed 's/.∗.$/\2/'    #删除该行除最后一个字符外的所有字符,保留最后一个字符,也即取得该行最后一个字符。

Shell 的一些注意事项

1. 基础

#!/bin/bash   //bash脚本第一句都是这个,他会让系统指定以bash来解释这个脚本

#  : shell脚本注释符号

2.变量

变量赋值的时候"="两边的内容要紧靠"="

3. 在使用if、while时,注意变量与符号之间的分割

例如:if [ `expr $a % 3` -ne 0 ],while [ "$var" != "end" ],尽量分开写,这样也挺好看也便于识别。

4. let的意思是让"="后面的内容做算术运算**,例如:let x=a-b

5. 大多数情况下,可以使用测试命令来对条件进行测试

比如可以比较字符串、判断文件是否存在及是否可读等等……通常用" [ ] "来表示条件测试,注意这里的空格很重要, 要确保方括号前后的空格

1[ -f "somefile" ] :判断是否是一个文件
2
3[ -x "/bin/ls" ] :判断/bin/ls是否存在并有可执行权限
4
5[ -n "$var" ] :判断$var变量是否有值
6
7[ "$a" = "$b" ] :判断$a$b是否相等