个人专题目录
1. Shell解析器
- Linux提供的Shell解析器有:
$ cat /etc/shells
/bin/sh
/bin/bash
/sbin/nologin
/bin/dash
/bin/tcsh
/bin/csh
- bash和sh的关系
$ ll /bin | grep bash
-rwxr-xr-x. 1 root root 941880 5月 11 2016 bash
lrwxrwxrwx. 1 root root 4 5月 27 2017 sh -> bash
- Centos默认的解析器是bash
$ echo $SHELL
/bin/bash
2. Shell脚本入门
- 脚本格式
脚本以#!/bin/bash开头(指定解析器)这一行决定了脚本可以像一个独立的可执行文件一样执行,而不用在终端之前输入sh
,bash
,python
,php
等。
- 第一个Shell脚本:helloworld
- 需求:创建一个Shell脚本,输出helloworld
- 案例实操:
$ touch helloworld.sh
$ vi helloworld.sh
在helloworld.sh中输入如下内容
#!/bin/bash
echo "helloworld"
- 脚本的常用执行方式
第一种:采用bash或sh+脚本的相对路径或绝对路径(不用赋予脚本+x权限)
# sh+脚本的相对路径
$ sh helloworld.sh
#sh+脚本的绝对路径
$ sh /home/xubh/datas/helloworld.sh
helloworld
#bash+脚本的相对路径
$ bash helloworld.sh
Helloworld
#bash+脚本的绝对路径
$ bash /home/xubh/datas/helloworld.sh
Helloworld
第二种:采用输入脚本的绝对路径或相对路径执行脚本(必须具有可执行权限+x)
# 首先要赋予helloworld.sh 脚本的+x权限
$ chmod 777 helloworld.sh
# 执行脚本
# 相对路径
$ ./helloworld.sh
Helloworld
# 绝对路径
$ /home/xubh/datas/helloworld.sh
Helloworld
注意:第一种执行方法,本质是bash解析器帮你执行脚本,所以脚本本身不需要执行权限。第二种执行方法,本质是脚本需要自己执行,所以需要执行权限。
- 第二个Shell脚本:多命令处理
# 在/home/xubh/目录下创建一个banzhang.txt,在banzhang.txt文件中增加“I love cls”。
$ touch batch.sh
$ vi batch.sh
在batch.sh中输入如下内容
#!/bin/bash
cd /home/xubh
touch cls.txt
echo "I love cls" >>cls.txt
3. Shell中的变量
系统变量
- 常用系统变量
PWD、USER等
- 案例实操
# 查看系统变量的值
$ echo $HOME
/home/xubh
# 显示当前Shell中所有变量:set
$ set
BASH=/bin/bash
BASH_ALIASES=()
BASH_ARGC=()
BASH_ARGV=()
自定义变量
-
基本语法
- 定义变量:变量=值
- 撤销变量:unset 变量
- 声明静态变量:readonly变量,注意:不能unset
-
变量定义规则
- 变量名称可以由字母、数字和下划线组成,但是不能以数字开头,环境变量名建议大写。
- 等号两侧不能有空格
- 在bash中,变量默认类型都是字符串类型,无法直接进行数值运算。
- 变量的值如果有空格,需要使用双引号或单引号括起来。
案例实操
# (1)定义变量A
$ A=5
$ echo $A
5
#(2)给变量A重新赋值
$ A=8
$ echo $A
8
#(3)撤销变量A
$ unset A
$ echo $A
#(4)声明静态的变量B=2,不能unset
$ readonly B=2
$ echo $B
2
$ B=9
-bash: B: readonly variable
#(5)在bash中,变量默认类型都是字符串类型,无法直接进行数值运算
$ C=1+2
$ echo $C
1+2
#(6)变量的值如果有空格,需要使用双引号或单引号括起来
$ D=I love banzhang
-bash: world: command not found
$ D="I love banzhang"
$ echo $A
I love banzhang
#(7)可把变量提升为全局环境变量,可供其他Shell程序使用
$ vim helloworld.sh
在helloworld.sh文件中增加echo $B
#!/bin/bash
echo "helloworld"
echo $B
$ ./helloworld.sh
Helloworld
# 发现并没有打印输出变量B的值。
$ export B
$ ./helloworld.sh
helloworld
2
Array
像其它语言一样,bash 也有数组类型。bash 中的数组是一个保存着很多值的变量,数组的长度没有限制,下标也是从 0 开始。在 bash 中有好几种方法创建一个数组,如下所示。
Examples:
array[0] = val
array[1] = val
array[2] = val
array=([2]=val [0]=val [1]=val)
array=(val val val)
使用如下语法获得数组特定位置的值:
${array[i]} # i是数组下标
如果没有指定数组下标,默认返回第一个元素。想知道数组中有多少个元素,使用下面的语法:
${#array[@]}
Bash 也支持三元运算符,如下面的例子所示:
${varname:-word} # 如果 varname 存在而且不为 null,返回它的值,否则返回 word
${varname:=word} # 如果 varname 存在而且不为 null,返回它的值,否则把word赋值给它并且返回 word
${varname:+word} # 如果 varname 存在而且不为 null,返回 word,否则返回 null
${varname:offset:length} # 它返回 $varname 的子字符串,从 offset 处开始,长度为 length
String Substitution
${variable#pattern} # 如果 pattern 匹配变量值的起始部分,删除匹配 pattern 的最短的部分,然后返回剩余的
${variable##pattern} # 如果 pattern 匹配变量值的起始部分,删除匹配 pattern 的最长的部分,然后返回剩余的
${variable%pattern} # 如果 pattern 匹配变量值的结束部分,删除匹配 pattern 的最短的部分,然后返回剩余的
${variable%%pattern} # 如果 pattern 匹配变量值的结束部分,删除匹配 pattern 的最长的部分,然后返回剩余的
${variable/pattern/string} # 把变量值中匹配 pattern 的最长的部分替换为 string,只替换第一个匹配的部分
${variable//pattern/string} # 把变量值中匹配 pattern 的最长的部分替换为 string,全局进行替换
${#varname} # 返回变量值作为一个字符串的长度
特殊变量:$n
- 基本语法
0代表该脚本名称,9代表第一到第九个参数,十以上的参数,十以上的参数需要用大括号包含,如${10})
-
案例实操
- 输出该脚本文件名称、输入参数1和输入参数2 的值
$ touch parameter.sh
$ vim parameter.sh
#!/bin/bash
echo "$0 $1 $2"
$ chmod 777 parameter.sh
$ ./parameter.sh cls xz
./parameter.sh cls xz
特殊变量:$#
- 基本语法
$#(功能描述:获取所有输入参数个数,常用于循环)。
-
案例实操
- 获取输入参数的个数
$ vim parameter.sh
#!/bin/bash
echo "$0 $1 $2"
echo $#
$ chmod 777 parameter.sh
$ ./parameter.sh cls xz
parameter.sh cls xz
2
特殊变量:@
- 基本语法
*把所有的参数看成一个整体)
@把每个参数区分对待)
-
案例实操
- 打印输入的所有参数
$ vim parameter.sh
#!/bin/bash
echo "$0 $1 $2"
echo $#
echo $*
echo $@
$ bash parameter.sh 1 2 3
parameter.sh 1 2
3
1 2 3
1 2 3
特殊变量:$?
- 基本语法
$? (功能描述:最后一次执行的命令的返回状态。如果这个变量的值为0,证明上一个命令正确执行;如果这个变量的值为非0(具体是哪个数,由命令自己来决定),则证明上一个命令执行不正确了。)
-
案例实操
- 判断helloworld.sh脚本是否正确执行
$ ./helloworld.sh
hello world
$ echo $?
0
4. 运算符
-
基本语法
- “[运算式]”
- expr + , - , *, /, % 加,减,乘,除,取余
- 注意:expr运算符间要有空格
- 案例实操:
#(1)计算3+2的值
$ expr 2 + 3
5
#(2)计算3-2的值
$ expr 3 - 2
1
#(3)计算(2+3)X4的值
#(a)expr一步完成计算
$ expr `expr 2 + 3` \* 4
20
#(b)采用$[运算式]方式
# S=$[(2+3)*4]
# echo $S
5. 条件判断
- 基本语法
[ condition ](注意condition前后要有空格)
注意:条件非空即为true,[xubh]返回true,[] 返回false。
- 常用判断条件
- 两个整数之间比较
= 字符串比较
-lt 小于(less than) -le 小于等于(less equal)
-eq 等于(equal) -gt 大于(greater than)
-ge 大于等于(greater equal) -ne 不等于(Not equal)
- 按照文件权限进行判断
-r 有读的权限(read)
-w 有写的权限(write)
-x 有执行的权限(execute)
- 按照文件类型进行判断
-f 文件存在并且是一个常规的文件(file)
-e 文件存在(existence)
-d 文件存在并是一个目录(directory)
- 案例实操
#(1)23是否大于等于22
$ [ 23 -ge 22 ]
$ echo $?
0
#(2)helloworld.sh是否具有写权限
$ [ -w helloworld.sh ]
$ echo $?
0
#(3)/home/xubh/cls.txt目录中的文件是否存在
$ [ -e /home/xubh/cls.txt ]
$ echo $?
1
#(4)多条件判断(&& 表示前一条命令执行成功时,才执行后一条命令,|| 表示上一条命令执行失败后,才执行下一条命令)
$ [ condition ] && echo OK || echo notok
OK
$ [ condition ] && [ ] || echo notok
notok
6. 流程控制
if 判断
- 基本语法
if [expression]; then
will execute only if expression is true
else
will execute if expression is false
fi
注意事项:
[ 条件判断式 ],中括号和条件判断式之间必须有空格
if后要有空格
-
案例实操
- 输入一个数字,如果是1,则输出banzhang zhen shuai,如果是2,则输出cls zhen mei,如果是其它,什么也不输出。
$ touch if.sh
$ vim if.sh
#!/bin/bash
if [ $1 -eq "1" ]
then
echo "banzhang zhen shuai"
elif [ $1 -eq "2" ]
then
echo "cls zhen mei"
fi
statement1 && statement2 # 两个语句都为真
statement1 || statement2 # 至少一个语句为真
str1=str2 # str1 匹配 str2
str1!=str2 # str1 不匹配 str2
str1str2 # str1 大于 str2
-n str1 # str1 不是 null (长度大于 0)
-z str1 # str1 是 null (长度为 0)
-a file # 文件存在
-d file # 文件存在而且是目录
-e file # 文件存在,跟 -a 一样
-f file # 文件存在,而且是常规文件(不是目录或者其他特殊类型的文件)
-r file # 你有读权限
-s file # 文件存在而且不为空
-w file # 你有写权限
-x file # 你对文件有执行权限,如果 file 是目录的话,你对它有搜索权限
-N file # 从上次读之后文件被修改过
-O file # 你是文件所有者
-G file # 文件的 group ID 跟你的 group ID (或之一,如果你在很多分组里)相同
file1 -nt file2 # file1 比 file2 更新
file1 -ot file2 # file1 比 file2 更老
-lt # 小于
-le # 小于等于
-eq # 等于
-ge # 大于等于
-gt # 大于
-ne # 不等于
$ chmod 777 if.sh
$ ./if.sh 1
banzhang zhen shuai
case 语句
- 基本语法
case $变量名 in
"值1")
如果变量的值等于值1,则执行程序1
;;
"值2")
如果变量的值等于值2,则执行程序2
;;
…省略其他分支…
*)
如果变量的值都不是以上的值,则执行此程序
;;
esac
注意事项:
- case行尾必须为单词“in”,每一个模式匹配必须以右括号“)”结束。
- 双分号“;;”表示命令序列结束,相当于java中的break。
- 最后的“*)”表示默认模式,相当于java中的default。
-
案例实操
- 输入一个数字,如果是1,则输出banzhang,如果是2,则输出cls,如果是其它,输出renyao。
$ touch case.sh
$ vim case.sh
!/bin/bash
case $1 in
"1")
echo "banzhang"
;;
"2")
echo "cls"
;;
*)
echo "renyao"
;;
esac
$ chmod 777 case.sh
$ ./case.sh 1
1
for 循环
-
基本语法1
for (( initialisation ; ending condition ; update ))
do
statements...
done
```
-
案例实操
- 从1加到100
$ touch for1.sh
$ vim for1.sh
#!/bin/bash
s=0
for((i=0;i<=100;i++))
do
s=$[$s+$i]
done
echo $s
$ chmod 777 for1.sh
$ ./for1.sh
“5050”
- 基本语法2
for name [in list]
do
statements that can use $name
done
- 案例实操
- 打印所有输入参数
$ touch for2.sh
$ vim for2.sh
#!/bin/bash
#打印数字
for i in $*
do
echo "ban zhang love $i "
done
$ chmod 777 for2.sh
$ bash for2.sh cls xz bd
ban zhang love cls
ban zhang love xz
ban zhang love bd
- 比较@区别
(a)@都表示传递给函数或脚本的所有参数,不被双引号“”包含时,都以2 …$n的形式输出所有参数。
$ touch for.sh
$ vim for.sh
#!/bin/bash
for i in $*
do
echo "ban zhang love $i "
done
for j in $@
do
echo "ban zhang love $j"
done
$ bash for.sh cls xz bd
ban zhang love cls
ban zhang love xz
ban zhang love bd
ban zhang love cls
ban zhang love xz
ban zhang love bd
(b)当它们被双引号“”包含时,“1 n”的形式输出所有参数;“1” “n”的形式输出所有参数。
$ vim for.sh
#!/bin/bash
for i in "$*"
#$*中的所有参数看成是一个整体,所以这个for循环只会循环一次
do
echo "ban zhang love $i"
done
for j in "$@"
#$@中的每个参数都看成是独立的,所以“$@”中有几个参数,就会循环几次
do
echo "ban zhang love $j"
done
$ chmod 777 for.sh
$ bash for.sh cls xz bd
ban zhang love cls xz bd
ban zhang love cls
ban zhang love xz
ban zhang love bd
while 循环
- 基本语法
while condition; do
statements
done
- 案例实操
- 从1加到100
$ touch while.sh
$ vim while.sh
#!/bin/bash
s=0
i=1
while [ $i -le 100 ]
do
s=$[$s+$i]
i=$[$i+1]
done
echo $s
$ chmod 777 while.sh
$ ./while.sh
5050
7. read读取控制台输入
- 基本语法
read(选项)(参数)
选项:
-p:指定读取值时的提示符;
-t:指定读取值时等待的时间(秒)。
参数
变量:指定读取值的变量名
- 案例实操
(1)提示7秒内,读取控制台输入的名称
$ touch read.sh
$ vim read.sh
#!/bin/bash
read -t 7 -p "Enter your name in 7 seconds " NAME
echo $NAME
$ ./read.sh
Enter your name in 7 seconds xiaoze
xiaoze
8. 函数
系统函数
- basename基本语法
basename [string / pathname] [suffix] (功能描述:basename命令会删掉所有的前缀包括最后一个(‘/’)字符,然后将字符串显示出来。
选项:
suffix为后缀,如果suffix被指定了,basename会将pathname或string中的suffix去掉。
- 案例实操
- 截取该/home/xubh/banzhang.txt路径的文件名称
$ basename /home/xubh/banzhang.txt
banzhang.txt
$ basename /home/xubh/banzhang.txt .txt
banzhang
- dirname基本语法
dirname 文件绝对路径(功能描述:从给定的包含绝对路径的文件名中去除文件名(非目录的部分),然后返回剩下的路径(目录的部分))
-
案例实操
- 获取banzhang.txt文件的路径
$ dirname /home/xubh/banzhang.txt
/home/xubh
自定义函数
- 基本语法
[ function ] funname[()]
{
Action;
[return int;]
}
funname
-
经验技巧
1.必须在调用函数地方之前,先声明函数,shell脚本是逐行运行。不会像其它语言一样先编译。
2.函数返回值,只能通过$?系统变量获得,可以显示加:return返回,如果不加,将以最后一条命令运行结果,作为返回值。return后跟数值n(0-255)
-
案例实操
计算两个输入参数的和
$ touch fun.sh
$ vim fun.sh
#!/bin/bash
function sum()
{
s=0
s=$[ $1 + $2 ]
echo "$s"
}
read -p "Please input the number1: " n1;
read -p "Please input the number2: " n2;
sum $n1 $n2;
$ chmod 777 fun.sh
$ ./fun.sh
Please input the number1: 2
Please input the number2: 5
7