Shell 是一种特殊功能的程序,它介于用户和 unix/linux 操作系统内核程序之间的一个接口,通过 SSH 服务连接到 shell 就可进行远程操作了。
shell 中的变量
- 用户自定义变量, 用户在 bash 窗口或者 shell 脚本中临时定义的变量
- 位置变量, $0,$1,$2….用来获取传入参数及程序名称($0)
- 预定义变量(系统变量),
$#,$*,$@,$?,$$,$!
这些变量只能使用不能修改 - 环境变量, 系统中默认存在的变量如:$PWD, $PATH, 可以通过
export
导出, 导出的变量可以穿透多层 bash/shell。一般变量可以直接在 shell 中赋值创建(如:a=1)或使用set a=1
,二者是等价的,如果想删除变量使用unset <变量名>
。
变量名 | 含义 |
---|---|
$# |
命令行参数数量 |
$0 |
当前程序(脚本)名称, 带路径, 通过 sh/bash 执行的脚本名称中不含路径 |
$? |
前一个命令或函数的返回值 |
$* |
以 “参 1 参 2 参 3 …” 返回所有参数, 此时所有参数是以空格分割的一个字符串 |
$@ |
以"参 1" “参 2” “参 3” …返回所有参数, 此时每个参数都是一个字符串 |
$$ |
本程序(脚本)的进程号 PID) |
$! |
上个命令的进程号 |
几个特殊引用
- 双引号: 括起来的字符除了
$
(美元符)、\
(反引号)、"
(双引号)、`(反引号)之外其他的均视为普通字符对待. - 单引号: 括起来的字符都视为普通字符,普通字符直接被打印
- 反引号: 反引号括起来的字符串会被 shell 解释为命令, 就像在 shell 中输入命令一样, 注意: 在反双引号中不能用命令的别名
脚本中常用变量替换
${var}
取出 var 变量的值${var:-var2}
var 为空或已被删除或未定义, 则表达式返回 var2, 不改变 var 的值${var:+var2}
var 未定义, 则返回 var2, 不改变 var 的值${var:=var2}
var 为空或已被删除或未定义, 则表达式返回 var2, 改变 var 的值!, 如果已被删除或未定义会重新创建变量${var:?msg}
如果 var 为空或已被删除或未定义, 则在控制台标准输出打印 msg, 可以用来检测变量 var 是否被赋值. 当出现这种替换, 脚本将停止运行.
字符串变量的截取
${#str}
求 str 的串长${str:3}
从第 3 个字符截取到最后一个字符(含第 3 个)${str:3:5}
从第 3 个字符截取到第 5 个字符(含第 3 第 5 个)
sehll 中变量计算
$(())
, 在两个括号中可以放置需要计算的变量表达式$[]
, 在中括号中放入表达式let
, let sum=1+2expr
, 如: sum="expr 1 + 2"
, 注意:+
好两端要有空格!
read – 读取变量命令
该用在 shell 脚本中, 读取一个变量并赋值, 如果指定多个变量但输入参数数量超过时, 多的参数赋值在最后个接收的变量. 参数:
- -p 后面跟提示信息, 当用户输入时显示提示信息
- -n 指定 read 读入文本长度
- -s 静默输入, 输入字符时不显示在屏幕上
echo
常用参数:
- -n 在屏幕打印后不换行
- -e 启用反斜杠转义功能,对
\n
之类转义字符进行转义,否则作为普通字符输出 - -E 此项为缺省项, 不对转义字符做特殊处理
常用转义字符
转义字符 | 含义 |
---|---|
\n |
换行 |
-r |
回车, 换到下一行并将光标置于行首 |
\r |
制表符 |
\b |
退格,左删除 |
\\ |
斜杠本身 |
shell 中比较和判断
在 shell 中 0 代表的是真, 非零代表为假, 这一点与 C/C++截然相反的.
数值比较表达式
test 表达式的两种形式: test var -eq var2
[ var -eq var2 ]
test 表达式 | 含义 |
---|---|
var -eq var2 | 判断两变量是否相等 |
var -ge var2 | 判断 var 是否大于等于 var2 |
var -le var2 | 判断 var 是否小于等于 var2 |
var -gt var2 | 判断 var 是否大于 var2 |
var -lt var2 | 判断 var 是否小于 var2 |
var -ne var2 | 判断 var 是否不等于 var2 |
类型判断表达式
test 表达式 | 含义 |
---|---|
-d file | 判断 file 是否为目录 |
-f file | 判断 file 是否为文件 |
-r file | 判断文件是否可读 |
-w file | 判断文件是否可写 |
-x file | 判断文件是否可以执行 |
-s file | 判断文件内容长度是否大于 0 |
判断字符串
test 表达式 | 含义 |
---|---|
= | 等于则为真 |
!= | 不相等则为真 |
-z 字符串 | 字符串的长度为零则为真 |
-n 字符串 | 字符串的长度不为零则为真 |
逻辑判断表达式
test 表达式 | 含义 |
---|---|
!var | var=假/0, 返回真 |
var1 -a var2 | var1 和 var2 同时为真才返回真,否则返回假 |
var1 -o var2 | var1 和 var2 至少有一个为真是返回真,否则返回假 |
注意事项 变量测试表达式一般不单独使用, 常常作为 for/if 的条件.
shell 的分支循环结构
if 结构
1#!/bin/bash
2
3let var=2
4# 常用写法
5if [ $var -eq 0 ]
6then
7 echo "var is 0"
8fi
9
10# 常用写法2
11if [ $var -eq 0 ]; then
12 echo "var is 0"
13fi
14
15# 直接写test方式
16if test $var -eq 0
17then
18 echo "var is 0"
19fi
20
21# if-else
22if [ $var -eq 0 ]
23then
24 echo "var is 0"
25else
26 echo "var is other number."
27fi
28
29# if-elif-else
30if [ $var -eq 0 ]
31then
32 echo "var is 0"
33elif [ $var -eq 1 ]
34then
35 echo "var is 1"
36else
37 echo "var is other number."
38fi
case 结构
case 结构与常见语言的 switch 语句相似, 不同的是每个 case 分支结束时用双分号;;
.
1#!/bin/bash
2
3read -p "please intput a animal name: " a
4# 匹配字符串
5case $a in
6cat)
7 echo "this is a cat."
8 ;;
9fish)
10 echo "this is a fish."
11 ;;
12*)
13 echo "another animal."
14esac
15
16# 匹配数字
17case $a in
181)
19 echo "match number 1"
20 ;;
212)
22 echo "match number 2"
23 ;;
24*)
25 echo "unknow number: $a"
26esac
for 结构
1#!/bin/bash
2
3echo "-----------"
4echo "all args:$*"
5echo "all args:$@"
6echo "-----------"
7
8# 常用, $*可以替换为$@,都获取执行脚本时所有参数
9for a in $*
10do
11 echo "$a"
12done
13
14# 循环1到5, in后面的{}中为一组内容,数字或文本都可
15# {1..5} 等价于 {1,2,3,4,5}
16for a in {1,2,3,4,5}
17do
18 echo "$a"
19done
20
21# 循环1到5
22for a in 1 2 3 4 5
23do
24 echo "$a"
25done
26
27# C语言风格, 循环1~5
28for (( i=1; i<=5; i++ ))
29do
30 echo "$i"
31done
32
33# -------------
34# 输出当前目录中以.sh结尾的文件
35for n in `ls *.sh`
36{
37 echo $n
38}
39
40# 输出 1~10,{1..10} 产生1~10序列,等价于 seq 10
41for a in {1..10}
42{
43 echo $a
44}
while 结构
在 while 改变变量的值使用let
或 var=$[express], 其中 var 为一个变量,express 为一个运算表达式,如 1+2
1**#!/bin/bash
2
3let var=1
4
5# 常用, 循环1~5
6while [ $var -le 5 ]
7do
8 echo "$var"
9 let var=$var+1
10done
11
12let var=1
13while [ $var -le 5 ]
14do
15 echo "$var"
16 let var++
17done
until
当条件为假时执行循环, 其使用同while
.
循环控制语句
中断语句:
- break: 用来终止循环, 如果是前嵌套循环 break 后可以跟一个数字 n, 表示退出第 n 重循环(最内的循环为第一重)
- continue: 用来跳过(忽略)本次循环, 如果是嵌套循环, continue 后可以跟一个数字 n, 表示回到第 n 重循环的顶部
1#!/bin/bash
2
3let var=1
4
5# 常用, 循环0~5
6while [ $var -le 5 ]
7do
8 if [ $var -eq 2 ]
9 then
10 echo "now var=$var, break while."
11 break
12 fi
13
14 echo "$var"
15 let var=$var+1
16done
17
18echo "----------------------"
19
20let var=1
21while [ $var -le 5 ]
22do
23
24 if [ $var -eq 2 ]
25 then
26 echo "now var=$var, conticned the second cycle."
27 break
28 fi
29
30 echo "$var"
31 let var++
32done
函数
函数的在 shell 中是独立的一段代码,实现一些功能的复用。
函数要点:
- 函数可以接收参数,同 shell 脚本接收参数方式相同,使用$*,$@,$1
- 函数体中获取参数的变量($*,$@,$1)获取的是函数自己的参数
定义方式
1#!/bin/bash
2
3# 定义函数方式1
4fun1()
5{
6 echo "called fun1"
7}
8
9# 定义函数方式2
10function fun2
11{
12 echo "called fun2"
13}
14
15#调用函数
16fun1
17fun2
函数实现递归
1#!/bin/bash
2# 通过读取脚本的第一输入参数值求其阶乘, 并输出结果
3
4# 递归求阶乘函数
5function jie
6{
7 if [ $1 -le 1 ]
8 then
9 echo 1
10 else
11 x=`jie $[$1-1]`
12 echo $[$1*x]
13 fi
14}
15
16# 调用计算
17res=$(jie $1) # 此处函数jie接收的第一个参数为此脚本运行时的第一个参数
18echo "res=$res" # 接收echo输出的返回值
数组
在 shell 中数组与高级编程语言中的数组时有区别的, 在声明方面可以用declare -a arr
声明 arr 数组, 参数-a 是声明数组的意思, 除此之外 declare 还可以声明函数, 其次当我们使用 declare 声明一个数组时,下标越界不会有报错提示.
declare 后的参数
-a 声明数组 -i 声明 integer 整数 -r 声明变量定义为只读 -f 定义为函数
数组的使用
1#!/bin/bash
2
3declare -a arr[10]
4# 即使下标越界(i>=10)也不会报错
5for ((i=0;i<10;i++))
6{
7 arr[i]=$[i+1]
8}
9
10# 输出
11for ((k=0;k<10;k++))
12{
13 echo ${arr[k]}
14}
总结
学完以上只是对 shell 编程的一个入门, 如果把一下常用的命令(如: awk、sed、grep、find)结合进脚本,功能就会大大增强.
在写 test 判断表达式时尽量每个部分之间都一个空格,以免出现格式操作。注意: expr 的运算符两边是必须要留空格的。总之多留一些空格可以避免一些语法错误。
for 可以遍历的内容很多, 不仅仅是数组, 在 in 后可以放置命令的执行结果(以空格分割)