1.简介
shell脚本执行方式Shell 是一个用 C 语言编写的程序,通过 Shell 用户可以访问操作系统内核服务。它类似于 DOS 下的 command 和后来的 cmd.exe。Shell 既是一种命令语言,又是一种程序设计语言。
Shell script 是一种为 shell 编写的脚本程序。Shell 编程一般指 shell脚本编程,不是指开发 shell 自身。
Shell 编程跟 java、php 编程一样,只要有一个能编写代码的文本编辑器和一个能解释执行的脚本解释器就可以了。
Linux 的 Shell 种类众多,一个系统可以存在多个 shell,可以通过 cat /etc/shells 命令查看系统中安装的 shell。
Bash 由于易用和免费,在日常工作中被广泛使用。同时,Bash 也是大多数Linux 系统默认的 Shell。
2.快速入门
-
1.#!是一个约定的标记,它告诉系统这个脚本需要什么解释器来执行,即使用哪一种 Shell。注意,在shell脚本中除了第一行的#表示特殊格式外,其他地方的#一般表示注释。
echo命令用于向窗口输出文本。touch hello.sh # 新建一个.sh文件 vim hello.sh # vim编辑此文件 #文件里编写下面 #!/bin/bash echo 'hello world'
3.解释器
- Java需要虚拟机解释器, 同理 shell脚本也需要解析器,查看Linux系统支持的解释器:
cat /etc/shells
/bin/sh
/bin/bash
/sbin/nologin
/bin/dash
/bin/tcsh
/bin/csh
- 4.常见Shell解释器
- sh:的全称是Bourne shell,由 AT&T 公司的 Steve Bourne开发,为了纪念他,就用他的名字命名了。sh 是UNIX 上的标准 shell,很多 UNIX 版本都配有 sh。sh 是第一个流行的 Shell。
- Bash:从名称可以看出是Bsh的升级版本,是著名的开源软件项目,目前大多数的Linux版本都使用Bash作为默认的Shell程序,当运行Shell程序时,实际运行的是Bash程序
- Csh:是因使用C语言的语法风格而得名,在用户的命令行交互界面上进行了很多改进,并增加了历史,别名,文件名替换,作业掏等功能,相比Bsh,Csh在更加适用为 用户提供命令交互操作
在现代的 Linux上,sh 已经被 bash 代替,/bin/sh往往是指向/bin/bash的符号链接。
如果你希望查看当前 Linux的默认 Shell,那么可以输出 SHELL 环境变量
[root@node1 shell]# echo $SHELL
/bin/bash
5.shell脚本执行方式
- shell脚本有三种执行方式
- sh执行
sh执行,进入脚本的工作目录,然后使用对应的sh或bash来执行脚本,这种执行方式,脚本文件不需要具有可执行权限
[root@node1 ~]#sh hello.sh
hello world - 工作目录执行
执行脚本时,先进入到脚本所在的目录,然后使用 ./脚本方式执行,这种执行方式,必须保证脚本文件具有可执行权限
[root@node1 shell]# chmod 777 hello.sh
[root@node1 shell]# ./hello.sh
hello world - 绝对路径执行
绝对路径中执行,指的是直接从根目录/到脚本目录的绝对路径,这种执行方式,必须保证脚本文件具有可执行权限
[root@node1 ~]# /root/hello.sh
hello
- sh执行
6.shell的数据类型
-
字符串:
字符串是shell编程中最常用最有用的数据类型,字符串可以用单引号,也可以用双引号,也可以不用引号。建议使用双引号,因为双引号里可以有变量和特殊字符,可以按照变量和特殊字符去使用。 -
整数型:
在Shell中所有的变量默认都是字符串型。默认情况下,所有的数值都是不能进行运算的,如果想要进行数学运算,可以使用“$((运算式))”或“$[运算式]”方式运算。
7.变量
-
shell变量是一种很“弱”的变量,默认情况下,一个变量保存一个串,shell不关心这个串是什么含义。所以若要进行数学运算,必须使用一些命令例如let、declare、expr、双括号等。
在shell中有3种变量:用户变量、环境变量、特殊变量,其中用户变量在编程过程中使用量最多,环境变量主要是在程序运行时需要设置,特殊变量在对参数判断和命令返回值判断时会使用。 -
变量的定义需遵循的规则
- 变量名可以由字母、数字和下画线组成,但是不能以数字开头。
- 在 Bash中,变量的默认类型都是字符串型,如果要进行数值运算,则必须使用特殊命令。
- 变量用等号"="连接值,"="左右两侧不能有空格。
- 变量值中如果有空格,则需要使用单引号或双引号包含,如 test="hello world!"。双引号括起 来的内容"$"和反引号者都拥有特殊含义,而单引号括起来的内容都是普通字符。
- 在变量值中,可以使用转义符""。
- 不能使用bash里的关键字(可用help命令查看保留关键字)。
8.用户变量
-
定义变量
在对变量赋于字符串值时,建议使用引号将其包裹。如果字符串中存在空格,请一定要使用单引号或双引号将整个内容包裹。注意:单引号里的内容原封不动的输出,双引号里有变量的调用则会调用变量
[root@node1 ~]# username="itcast" -
访问变量
要对变量进行调用时,在变量名前加美元符号$
[root@node1 ~]# echo $username
itcast
如果需要增加变量的值,那么可以进行变量值的叠加。不过变量需要用双引号包含"$变量名"或${变量名}
[root@node1 ~]# echo "$username"db.log
itcastdb.log
[root@node1 ~]# echo ${username}db.log
itcastdb.log -
测试脚本
脚本内容
#! /bin/bash
string="I am shell"
num=5
echo "a=${num},string=${string}"
执行脚本
[root@node1 ~]# sh test1.sh
a=5,string=I am shell
- 变量的其他赋值方式
1)可以使用read关键字从键盘获取内容赋值给变量
2)可以通过$(linux命令)或者$linux命令
来执行linux命令,并将命令的执行结果赋值给变量
脚本内容
#! /bin/bash
echo "who are you?"
read pwd #从键盘获取变量的值
pwd_string=$(pwd) #将当前的绝对路径赋值给pwd_string变量
date_string=`date` #将当前时间赋值给date_string变量
echo "hello, $name"
echo $pwd_string
echo $date_string
执行脚本
[root@node1 shell]# sh test2.sh
who are you?
itcast
hello, itcast
/export/data/shell
2021年 10月 25日 星期日 20:50:21 CST
- 只读变量
使用 readonly 命令可以将变量定义为只读变量,只读变量的值不能被改变。
下面的例子尝试更改只读变量,结果报错:
#!/bin/bash
jdUrl="http://www.jd.com"
readonly jdUrl
jdUrl="http://www.jingdong.com"
运行脚本,结果如下:
/bin/sh: NAME: This variable is read only.
- 删除变量
使用unset命令可以删除变量
unset variable_name
变量被删除后不能再次使用。unset 命令不能删除只读变量。
#!/bin/sh
taobaoUrl="http://www.taobao.com"
unset taobaoUrl
echo $taobaoUrl
以上实例执行将没有任何输出。
- 环境变量
当shell程序启动时,都自动设置一组变量,这组变量就是环境变量。shell中的所有命令都可以使用这些变量,环境变量可以在/etc/profile中设置,环境变量的名字习惯上使用大写字母- 常见的环境变量
PATH 决定了shell将到哪些目录中寻找命令或程序
HOME 当前用户主目录
HISTSIZE 历史记录数
LOGNAME 当前用户的登录名
HOSTNAME 指主机的名称
SHELL 当前用户Shell类型
LANGUGE 语言相关的环境变量,多语言可以修改此环境变量
MAIL 当前用户的邮件存放目录
PS1 基本提示符,对于root用户是#,对于普通用户是$
可以使用env命令查看所有的系统环境变量
- 常见的环境变量
[root@node1 shell]# env
XDG_SESSION_ID=2
HOSTNAME=node1
SELINUX_ROLE_REQUESTED=
TERM=xterm
SHELL=/bin/bash
HISTSIZE=1000
SSH_CLIENT=192.168.88.5 8047 22
CONDA_SHLVL=0
SELINUX_USE_CURRENT_RANGE=
SSH_TTY=/dev/pts/0
USER=root
- 自定义环境变量
- vim /etc/profile ,在文件末尾加上要定义的环境变量,语法如下:
export 变量名=变量值
export SERVICE_HOST=www.itcast.cn - wq 退出
- source /etc/profile
- 输入 env 查看环境变量,是否有自己定义的环境变量。
- 使用环境变量
环境变量的使用方式和普通变量是一样的:$环境变量名
[root@node1 shell]# echo $SERVICE_HOST
www.itcast.cn
- 特殊变量
我们可以在执行 Shell 脚本时,向脚本传递参数,这时候可以使用特殊变量来获取参数,Shell常用的特殊变量如下
$# 命令行参数的个数
$n $1表示第一个参数,$2表示第二个参数
$0 当前程序的名称
$? 前一个函数的返回码
$* 以“参数1 参数2 。。。”形式保存所有参数
$@ 同$*
$$ 本程序的PID
$! 上一个命令的PID
以下实例我们向脚本传递三个参数,并分别输出,其中 $0 为执行的文件名:
#!/bin/bash
echo "Shell 传递参数实例!";
echo "执行的文件名:$0";
echo "第一个参数为:$1";
echo "第二个参数为:$2";
echo "第三个参数为:$3";
echo "参数个数为:$#";
echo "传递的参数作为一个字符串显示*:$*";
执行脚本
[root@node1 ~]# chmod +x test5.sh
[root@node1 ~]# test5.sh aaa bbb ccc
Shell 传递参数实例!
执行的文件名:test5.sh
第一个参数为:aaa
第二个参数为:bbb
第三个参数为:ccc
参数个数为:3
传递的参数作为一个字符串显示*:aaa bbb ccc
$* 与 $@ 区别:
相同点:都是引用所有参数。
不同点:只有在双引号中体现出来。假设在脚本运行时写了三个参数 1、2、3,,则 " * " 等价于 "1 2 3"(传递了一个参数),而 "@" 等价于 "1" "2" "3"(传递了三个参数)。
9.字符串
字符串是shell编程中最常用最有用的数据类型(除了数字和字符串,也没啥其它类型好用了),字符串可以用单引号,也可以用双引号,也可以不用引号。
-
单引号
name='钱学森'
str='我很崇拜$name'
echo $str
输出结果为:
我很崇拜$name
单引号字符串的限制:
单引号里的任何字符都会原样输出,单引号字符串中的变量是无效的,单引号字串中不能出现单独一个的单引号(对单引号使用转义符后也不行),但可成对出现,作为字符串拼接使用。 -
拼接字符串
#脚本内容
#!/bin/bash
yourname="吴恩达"
wenhou_1="你好,$yourname ."
wenhou_2="你好,"$yourname" ."
wenhou_3="你好,\"$yourname\" ."
echo $wenhou_1 $wenhou_2 $wenhou_3
输出结果为:
你好,吴恩达 . 你好,吴恩达 . 你好,"吴恩达" .
- 获取字符串长度
#!/bin/bash
string="jobs"
echo ${string} # 输出结果: jobs
echo ${#string} # 输出结果: 4
- 提取字符串
以下实例从字符串第 2 个字符开始截取 4 个字符:
#!/bin/bash
str="敢于亮剑决不后退"
echo ${str:2:2} # 输出结果为: 亮剑 :2:2 从第二个位置开始切.步长为2
- 查找子字符串
查找字符 i 或 o 的位置(哪个字母先出现就计算哪个):#!/bin/bash string="i am a boy" echo `expr index "$string" am` # 输出是: 3 `是反引号
10.流程控制
-
算术运算符
Shell 和其他编程一样,支持包括:算术、关系、布尔、字符串等运算符。原生 bash 不支持简单的数学运算,但是可以通过其他命令来实现,例如expr。expr 是一款表达式计算工具,使用它能完成表达式的求值操作。
两个数相加:
val=expr 2+2
echo $val
注意:
表达式和运算符之间要有空格,例如 2+2 是不对的,必须写成 2 + 2。
完整的表达式要被
下表列出了常用的算术运算符,假定变量 a为10,变量b为20:
expr $a + $b
结果为 30。
expr $a - $b
结果为 -10。
expr $a \* $b
结果为 200。
expr $b / $a
结果为 2
expr $b % $a
结果为 0
a=$b 将把变量 b 的值赋给 a。
[ a == b ] 返回 false
[ a != b ] 返回 true。
注意:条件表达式要放在方括号之间,并且要有空格,例如: [a==b] 是错误的,必须写成 [ a == b ]。 -
数字
-eq 检测两个数是否相等,相等返回 true。
-ne 检测两个数是否不相等,不相等返回 true。
-gt 检测左边的数是否大于右边的,如果是,则返回 true
-lt 检测左边的数是否小于右边的,如果是,则返回 true。
-ge 检测左边的数是否大于等于右边的,如果是,则返回 true。
-le 检测左边的数是否小于等于右边的,如果是,则返回 true。 -
字符串
-n STRING 字符串长度不为0
-z STRING 字符串长度为0
= 判断两个字符串是否一样
!= 判断两个字符串是否不一样 -
文件
-f 存在且是普通文件
-d 存在且是目录
-h 存在且是符号链接
-e 文件存在
-r 文件存在并且可读
-w 文件存在并且可写
-z 文件存在并且可执行 -
if语句
-
判断当前系统是否有多个ssh进程,如果有则打印true
if [ $(ps -ef | grep -c "ssh") -gt 1 ] then echo "true" fi
-
判断/media/cdrom文件是否存在,若不存在就去创建这个目录(空格一定要注意!!!)
#!/bin/bash DIR="/media/cdrom" if [ ! -e $DIR ] then mkdir -p $DIR fi
-
-
if else
#!/bin/bash “”"Enter your age(1-100):" age if [ $age -ge 18 ] then echo '已经成年!' else echo '未成年!' fi
-
if else-if else
#!/bin/bash echo "请输入a的值:" read a echo "请输入b的值:" read b if [ $a == $b ] then echo "a 等于 b" elif [ $a -gt $b ] then echo "a 大于 b" elif [ $a -lt $b ] then echo "a 小于 b" else echo "没有符合的条件" fi
输入成绩,判断成绩“优”“良”“中”
#! /bin/bash read -p "Enter your score(0-100):" n #-p参数表示给出提示信息 if [ $n -ge 85 ] && [ $n -le 100 ] ; then echo "优" elif [ $n -ge 70 ] && [ $n -le 84 ] ; then echo "良" elif [ $n -ge 60 ] && [ $n -le 69 ] ; then echo "中" else echo "差" fi
-
for
当变量值在列表里,for循环即执行一次所有命令,使用变量名获取列表中的当前取值。命令可为任何有效的shell命令和语句。in列表可以包含替换、字符串和文件名。
in列表是可选的,如果不用它,for循环使用命令行的位置参数。- 顺序输出当前列表中的数字
#!/bin/bash for loop in 1 2 3 4 5 do echo "The value is: $loop" done 输出结果: The value is: 1 The value is: 2 The value is: 3 The value is: 4 The value is: 5
- 顺序输出字符串中的字符
#!/bin/bash for str in 'This is a string' do echo $str done 输出结果: This is a string
- 打印/root目录下所有文件的名字
#!/bin/bash for file in $(ls /root) do echo $file done
- 求1-100的和
#!/bin/bash s=0 #从1加到100 for(( i=1;i<=100;i=i+1)) #定义循环100次 do #每次循环给变量s赋值 s=$(($s+$i)) done #输出从1加到100的和 echo "The sum of 1+2+..+100 is : $s"
- 顺序输出当前列表中的数字
-
while循环
#!/bin/bash num=1 while(( $num<=5 )) do echo $num let "num++" done
-
case语句
#!/bin/bash while : do echo -n "输入 1 到 5 之间的数字:" read aNum case $aNum in 1|2|3|4|5) echo "你输入的数字为 $aNum!" ;; *) echo "你输入的数字不是 1 到 5 之间的! 游戏结束" break ;; esac done
11.函数
```
#!/bin/bash
funWithParam(){
echo "第一个参数为 $1 !"
echo "第二个参数为 $2 !"
echo "第十个参数为 $10 !"
echo "第十个参数为 ${10} !"
echo "第十一个参数为 ${11} !"
echo "参数总数有 $# 个!"
echo "作为一个字符串输出所有参数 $* !"
}
funWithParam 1 2 3 4 5 6 7 8 9 34 73
输出结果:
第一个参数为 1 !
第二个参数为 2 !
第十个参数为 10 !
第十个参数为 34 !
第十一个参数为 73 !
参数总数有 11 个!
作为一个字符串输出所有参数 1 2 3 4 5 6 7 8 9 34 73
```
12.数组
-
定义数组
数组中可以存放多个值。Bash Shell 只支持一维数组(不支持多维数组),初始化时不需要定义数组大小(与 PHP 类似)。
与大部分编程语言类似,数组元素的下标由0开始。
Shell 数组用括号来表示,元素用"空格"符号分割开,语法格式如下:
array_name=(value1 ... valuen) -
读取数组
${array_name[index]} -
获取数组中的所有元素
#!/bin/bash my_array[0]=“A” my_array[1]=“B” my_array[2]=“C” my_array[3]=“D” echo "数组的元素为: ${my_array[*]}" echo "数组的元素为: ${my_array[@]}" 输出: 数组的元素为: A B C D 数组的元素为: A B C D
-
获取数组的长度
echo "数组的元素个数为: ${#my_array[*]}"
echo "数组的元素个数为: ${#my_array[@]}" -
遍历数组
#!/bin/bash my_arr=(AA BB CC) for var in ${my_arr[*]} do echo $var done 或者 #!/bin/bash my_arr=(AA BB CC) my_arr_num=${#my_arr[*]} for((i=0;i<my_arr_num;i++)); do echo "-----------------------------" echo ${my_arr[$i]} done
13.加载其它文件的变量
和其他语言一样,Shell 也可以包含外部脚本。这样可以很方便的封装一些公用的代码作为一个独立的文件。
Shell 文件包含的语法格式如下:
. filename # 注意点号(.)和文件名中间有一空格
或
source filename
例:
source ./test1.sh # 加载test1.sh 的文件内容