shell
1.shell概述
Shell是命令解释器(command interpreter),是Unix操作系统的用户接口,程序从用户接口得到输入信息,shell将用户程序及其输入翻译成操作系统内核(kernel)能够识别的指令,并且操作系统内核执行完将返回的输出通过shell再呈现给用户,下图所示用户、shell和操作系统的关系:
一个系统可以存在多个shell,可以通过cat /etc/shells
命令查看系统中安装的shell。
[root@centos ~]# cat /etc/shells
/bin/sh
/bin/bash
/usr/bin/sh
/usr/bin/bash
/bin/tcsh
/bin/csh
操作系统内核(kernel)与shell是独立的套件,而且都可被替换;不同的操作系统使用不同的shell; 同一个kernel之上可以使用不同的shell。 也可以查看当前shell环境是哪种:
root@centos ~]# echo $SHELL
/bin/bash
shell脚本:可执行的Linux命令或语句不在命令行状态下执行,而是通过一个文件执行时,我们将这个文件称为shell脚本(可执行命令的组合)。在此脚本中,我们可以使用一些编程语法来进行一些任务操作。 如:变量、类型、分支结构、循环结构、数组、函数等语法。 在shell脚本里,必须指定一种shell命令解释器,它通过解释器解释运行。shell脚本文件的后缀为.sh
2.第一个shell脚本
- 编写脚本打印"hello shell"
#!/bin/bash
echo "hello shell"
- 脚本执行
[root@centos ~]# sh hello.sh
- 说明
1.脚本的第一行要写解析器的位置 声明用什么解释器来解释这个shell脚本
2.#!/bin/bash
3.要执行这个脚本,有两种方式
第一种:解析器的位置 脚本文件名
如:bash 文件名.sh
第二种运行方法:
修改文件的权限,添加执行权限
./文件名.sh
# 练习:写个shell脚本,显示你自己的名字
# 练习:新建两个文件夹,aa和bb,bb里有1.txt,aa里有2.txt,写个shell脚本,把aa,bb里的文件互换
- 注释
注释的文字不是代码的一部分,解析器看到你是注释文字,那么就不会进行解析
1.单行注释用#,#后面的所有文字都是注释,shell首行的#不是注释
2.多行注释:
:<<!
#echo 1111 #xxxx
2222
3333
!
编写一个脚本
提示用户输入 名字 性别 家庭地址
然后打印名字 性别 和 家庭地址(每行打印一个)
3.变量
3.1 什么是变量
- 变量是用来临时保存数据的,该数据是可以变化的数据。
- 如果某个内容需要多次使用,并且在代码中重复出现,那么可以用变量代表该内容。这样在修改内容的时候,仅仅需要修改变量的值。
3.2 变量的定义
3.2.1 变量的定义
-
变量名=变量值
变量名:用来临时保存数据的
变量值:就是临时的可变化的数据
变量名=变量值
[root@centos ~]# A=hello
3.2.2 变量的定义规则
1.变量名区分大小写
2.变量名不能有特殊符号
3.变量名不能以数字开头
4.不能使用bash中的关键字
5.变量名尽量做到见名知意
6.等号两边不能有任何空格
3.2.3 变量的定义方式
1.直接赋值给一个变量
[root@centos ~]# A=hello
2.命令执行结果赋值给变量
[root@centos ~]# B=`date +%F`
3.交互式定义变量 read
让用户自己给变量赋值
语法: read [选项] 变量名
# 只读变量
使用readonly来修饰变量,使变量成为只读变量,只读变量是不能修改的
[root@centos ~]# readonly B=shell
# 删除变量
使用unset可以删除一个变量
[root@centos ~]# unset A
read
常见选项:
选项 | 释义 |
---|---|
-p | 定义提示用户的信息 |
-n | 定义字符数(限制变量值的长度) |
-s | 不显示(不显示用户输入的内容) |
-t | 定义超时时间,默认单位为秒(限制用户输入变量值的超时时间) |
3.3 变量的使用
- 使用一个定义过的变量,只要在变量名前面加上
$
,就可以获取变量里的值
[root@centos ~]# A=hello
[root@centos ~]# echo $A
3.4 变量的分类
3.4.1 本地变量
- 当前用户自定义的变量,当前进程中有效,其他进程及当前进程的子进程无效
3.4.2 环境变量
- 当前进程有效,并且能够被子进程调用
env
查看当前用户的环境变量- 可以使用 ”
export
变量名=变量值“ 设置一个环境变量
3.4.3 全局变量
-
全局所有的用户和程序都能调用
-
解读相关配置文件
文件名 | 说明 | 备注 |
---|---|---|
~/.bashrc | 当前用户的bash信息,用户登录时读取 | 局部。定义别名、umask、函数等 |
~/.bash_profile | 当前用户的环境变量信息,用户登录时读取 | 局部。 |
~/.bash_logout | 当前用户退出当前shell时最后读取 | 局部。定义用户退出时执行的程序等 |
~/.bash_history | 当前用户的历史命令 | 局部。history -w 保存历史记录 history -c 清空历史记录 |
/etc/bashrc | 全局的bash信息 | 全局。所有用户都生效 |
/etc/profile | 全局环境变量信息 | 全局。系统和所有用户都生效 |
说明:以上文件修改后,都需要重新 source
让其生效或者退出重新登录。
3.4.4 系统变量
- shell本身已经固定好了它的名字和作用.
内置变量 | 含义 |
---|---|
$? | 上一条命令执行后返回的状态;状态值为0表示执行正常,非0表示执行异常或错误 |
$0 | 当前执行的程序或脚本名 |
$# | 脚本后面接的参数的个数 |
$* | 脚本后面所有参数,参数当成一个整体输出,每一个变量参数之间以空格隔开 |
$@ | 脚本后面所有参数,参数是独立的,也是全部输出 |
$1~$9 | 脚本后面的位置参数,$1表示第1个位置参数,依次类推 |
${10}~$ | 扩展位置参数,第10个位置变量必须用{}大括号括起来(2位数字以上扩起来) |
$$ | 当前所在进程的进程号,如echo $$ |
4.字符串操作
4.1 字符串概述
字符串:用引号包含的若干个字符组成的整体叫字符串
如:"12345","约吗?","1","2","hello world"
bash
中的引号
双引号"":弱引用,会把引号的内容当成整体来看待,允许通过$符号引用其他变量值
单引号'':强引用,会把引号的内容当成整体来看待,禁止引用其他变量值,shell中特殊符号都被视为普通字符
反撇号``:命令替换,反撇号和$()一样,引号或括号里的命令会优先执行,如果存在嵌套,反撇号不能用
4.2 字符串操作
1.字符串的拼接
把若干个字符串组合在一起的操作,叫字符串的拼接
#!/bin/bash
name="zhangsan"
p1="hello $name"
echo $p1 #打印出来显示hello zhangsan
p2="hello ${name}abc"
p3=$p1$p2
echo $p3 #hello zhangsanhello zhangsan
p4=$p1 $p2 #错误
p4="$p1 $p2"
echo $p4
2.获取字符串的长度(统计一下字符串中有多少个字符)
x="hello" --该字符串的长度为5
格式:${#变量名}
获取x变量中存储的字符串的长度
echo ${#x} #5
注意:字符串中有符号或空格也算一个字符
如:
y="hello world!"
echo ${#y} #12
3.截取字符串
格式:${变量名:开始截取的字符下标:截取的长度}
如:
x="zhangsan"
echo ${x:2:3}
注意:下标是从0开始数
4.3 字符串数组
1.数组:相同数据类型的数据集合
2.字符串数组:若干个字符串组成的集合叫字符串数组
3.shell中数组是没有大小限定
4.定义数组的格式:
数组名=(值1 值2 值3...)
5.数组里元素的位置是从0开始数,通常也叫数组的下标,可以针对数组里的位置单独放数据
如:
myarr=("aa" "bb" "cc")
myarr[0]="kk"
6.读取数组里的元素
1.格式:${数组名[下标]}
如要要取出上面数组中的bb元素,${myarr[1]}
2.把数组中的所有元素一次性取出,并打印
echo ${数组名[@]}
如要取出上面数组中所有的元素并打印
echo ${myarr[@]}
3.获取数组的长度(获取数组里有多少个元素)
${#myarr[@]}
4.获取数组中单个元素的长度
${#myarr[0]}
练习:写在脚本里:定义一个数组,把你所在省份的周边省放入到这个数组,然后在一个一个打印出来,每打印一个,还要在下面一行打印出该元素长度,最后一次性取出所有的元素,再打印数组的长度
5.运算符
5.1 算数运算符
-
算数运算:默认情况下,shell就只能支持简单的整数运算
-
运算内容:加(+)、减(-)、乘(*)、除(/)、求余数(%)
-
shell
进行数值运算的符号
表达式 | 举例 | 说明 |
---|---|---|
$(( )) | echo $((1+1)) | 可以进行复杂运算, * 号不需转义 |
$[ ] | echo $[10-5] | 可以进行复杂运算, * 号不需转义 |
expr | expr 10 / 5 | expr程序中,数值与运算符之间需要空格隔开,乘(*)运算符需要用转义符( \ )转义,expr不能做幂运算 |
let | n=1;let n+=1 等价于 let n=n+1 | let n*=2 等价于let n=n*2,不能使用let n**=2 |
5.2 关系运算符
判断参数 | 含义 |
---|---|
-eq | 相等 |
-ne | 不等 |
-gt | 大于 |
-lt | 小于 |
-ge | 大于等于 |
-le | 小于等于 |
5.3 逻辑运算符
判断符号 | 含义 | 举例 |
---|---|---|
-a 和 && | 逻辑与 | [ 1 -eq 1 -a 1 -ne 0 ] [ 1 -eq 1 ] && [ 1 -ne 0 ] |
-o 和 || | 逻辑或 | [ 1 -eq 1 -o 1 -ne 1 ] [ 1 -eq 1 ] || [1 -ne 1] |
&&
前面的表达式为真,才会执行后面的代码
||
前面的表达式为假,才会执行后面的代码
;
只用于分割命令或表达式
5.4 字符串运算符
判断参数 | 含义 |
---|---|
-z | 判断是否为空字符串,字符串长度为0则成立 |
-n | 判断是否为非空字符串,字符串长度不为0则成立 |
string1 = string2 | 判断字符串是否相等 |
string1 != string2 | 判断字符串是否相不等 |
5.5 文件测试运算符
-
test命令的作用:用于检测某个条件是否成立,它可以对数值,字符,和文件三个方面进行检测
-
判断文件类型
判断参数 | 含义 |
---|---|
-e | 判断文件是否存在(任何类型文件) |
-f | 判断文件是否存在并且是一个普通文件 |
-d | 判断文件是否存在并且是一个目录 |
-L | 判断文件是否存在并且是一个软连接文件 |
-s | 判断文件是否存在并且是一个非空文件(有内容) |
- 判断文件权限
判断参数 | 含义 |
---|---|
-r | 当前用户对其是否可读 |
-w | 当前用户对其是否可写 |
-x | 当前用户对其是否可执行 |
- 判断文件新旧
判断参数 | 含义 |
---|---|
file1 -nt file2 | 比较file1是否比file2新 |
file1 -ot file2 | 比较file1是否比file2旧 |
file1 -ef file2 | 比较是否为同一个文件,或者用于判断硬连接,是否指向同一个inode |
6.流程控制语句
6.1 if
结构
if [ 条件 ];then
命令
fi
if [ 条件 ]
then
命令
fi
if test 条件;then
命令
fi
if [[ 条件 ]];then
命令
fi
[ 条件 ] && command
6.2 if...else
结构
if [ 条件 ];then
命令1
else
命令2
fi
[ 条件 ] && 命令1 || 命令2
6.3 if...elif...else
结构
if [ 条件1 ];then
命令1
elif [ 条件2 ];then
命令2
else
命令3
fi
如果条件1满足,执行命令1后结束;如果条件1不满足,再看条件2,如果条件2满足执行命令2后结束;如果条件1和条件2都不满足执行命令3结束.
6.4 嵌套结构
if [ 条件1 ];then
命令1
if [ 条件2 ];then
命令2
fi
else
if [ 条件3 ];then
命令3
elif [ 条件4 ];then
命令4
else
命令5
fi
fi
如果条件1满足,执行命令1;如果条件2也满足执行命令2,如果不满足就只执行命令1结束;
如果条件1不满足,不看条件2;直接看条件3,如果条件3满足执行命令3;如果不满足则看条件4,如果条件4满足执行命令4;否则执行命令5
7.循环语句
7.1 for
循环语句
- 基本语法结构
for 变量 in {列表}
do
命令
done
# 或者
for 变量 in 值1 值2 值3
do
命令
done
# 或者
for (( expr1;expr2;expr3 ))
do
命令
done
循环打印1-5
1
2
3
4
5
i=i+1 i=i-1 i=i*1
i+=1 i-=1 i*=1
i++
for (( i=1;i<=5;i++ ))
do
echo $i
done
sum=0
for (( i=1;i<=100;i++ ))
do
sum=$[$sum+$i]
done
echo $sum
# expr1:定义变量并赋初值
# expr2:决定是否进行循环(条件)
# expr3:决定循环变量如何改变(决定循环什么时候退出)
7.2 while
循环语句
-
条件成立就进入循环,条件不成立则退出循环
-
基本语法
while 表达式
do
命令
done
for (( i=1;i<=100;i++ ))
do
命令
done
i=1
while (( i<=100 ))
do
命令
i=$[$i+1]
done
用while循环求1-100的累加和
while :
while (( 永真表达式 ))
while [ 1 -eq 1 ] 或者 (( 1 > 2 ))
do
命令
done
7.3 until
循环语句
-
条件为假就进入循环,条件为真就退出循环
-
语法结构
until 表达式
do
命令
done
直到满足表达式之前我都去进行循环
7.4 跳出循环 break
,continue
break
:打断;马上停止执行本次循环,执行循环体后面的代码continue
:继续;表示循环体内下面的代码不执行,重新开始下一次循环
a=10
while (( 1 ))
do
echo "一直停不下来 $a"
let "a++"
if [ $a == 16 ]
then
break
fi
done
n=0
while (( $n<100 ))
do
let "n++"
if [ $n == 66 -o $n == 88 -o $n == 99 ]
then
continue
fi
echo $n
done
7.5 嵌套循环
- 一个循环体内又包含另一个完整的循环结构,称为循环的嵌套。
- 每次外部循环都会触发内部循环,直至内部循环完成,才接着执行下一次的外部循环。
- for循环、while循环和until循环可以相互嵌套。
1
12
123
1234
12345
外部循环:打印换行,并且换5行 ,循环5次
内部循环:打印12345数字
for (( i=1;i<=5;i++ ))
do
for (( j=1;j<=$i;j++ ))
do
echo -n $j
done
echo
done
8. case
语句和函数
8.1 case
语句
case
语句为多重匹配语句,匹配成功则执行相应命令- 语法结构
说明:pattern表示需要匹配的模式
case var in
值1)
command1
;;
值2)
command2
;;
值3)
command3
;;
*) # default,不满足以上模式,默认执行*)下面的语句
command4
;;
esac # esac表示case语句结束
8.2 函数
- shell中允许将一组命令集合或语句形成一段可用代码,这些代码块称为shell函数
- 给这段代码起个名字称为函数名,后续可以直接调用该段代码的功能
- 函数声明
函数名()
{
函数体(一堆命令的集合,来实现某个功能)
}
或者
function 函数名()
{
函数体(一堆命令的集合,来实现某个功能)
}
- 函数调用
函数名 [参数]
- 函数的传参和返回值
1.函数传参
a.在Shell中,调用函数时可以向其传递参数。在函数体内部,通过 $n 的形式来获取参数的值,
例如,$1表示第一个参数,$2表示第二个参数...
但是,当n>=10时,需要使用${n}来获取参数值
如:
#!/bin/bash
add(){
c=`expr $1 + $2 `
echo "c=$c"
echo "${10}"
}
add 10 20
b.传递参数到函数内,在调用函数时,在函数名的旁边写参数
add 100 200 300 400 500 600 700 800 900 1000
练习:
1.写一个减法功能的函数,参数是从函数外部传递
#!/bin/bash
sub(){
a=`expr $1 - $2`
echo "结果:$a"
}
sub 20 10
2.写一个有加减乘除功能的函数,运算的数据和运算符都从外部传递到函数内
#!/bin/bash
n=0
count(){
case $3 in
"+")
n=`expr $1 + $2`
;;
"-")
n=`expr $1 - $2`
;;
"*")
n=`expr $1 \* $2`
;;
"/")
n=`expr $1 / $2`
;;
esac
echo "结果:$n"
}
count 20 10 "*"
2.函数的返回值
#!/bin/bash
add(){
c=`expr $1 + $2 `
echo "c=$c"
return $c
}
add 10 20
echo "$?"
注意:
1,shell中通过return返回是有限制的,只能返回整型,最大返回值是255
2,有多个函数返回时,在最后使用$?获取返回值时返回的是最后一个函数的返回值
#!/bin/bash
add(){
c=`expr $1 + $2 `
echo "c=$c"
return $c
}
add 10 20
add2(){
c=`expr $1 + $2 `
echo "c=$c"
return $c
}
add2 100 200
echo "$?"