目录
1 shell 脚本语言的基本用法
1.1 shell 脚本注释规范
1.1.1 shell 脚本注释规范
1.1.2 执行(5种)
1.1.3 在远程主机运行本地脚本
1.1.4 检查shell脚本
1.2 shell变量
1.2.1 Shell中变量命名法则
1.2.2 变量赋值与引用
1.2.3 环境变量的查看设置和删除
1.2.4 只读变量
1.2.5 位置变量
1.2.6 退出状态码变量
1.2.7 展开命令行
1.3 退出状态码变量
1.4 展开命令行
1.5 脚本安全和 set
1.6 格式化输出 printf命令
1.7 echo 命令
1.8 算术运算
1.9 短路运算
1.10 条件测试命令
1.10.1 条件测试命令
1.10.2 常用选项:文件判断相关
1.10.3 常用选项:字符串判断相关
1.10.4 常用选项:数学相关
1.10.5 变量测试
1.10.6 字符串测试
1.11 关于 () 和 {}
1.12 组合测试条件
2 bash shell 的配置文件
2.1 shell登录两种方式分类
2.2 按功能划分分类
2.3 编辑配置文件生效
2.4 Bash 退出任务
3 流程控制
3.1 选择执行 if 语句
3.2 条件判断 case 语句
3.3 循环的命令 for命令
3.3.1 方法 一
3.3.2 方法二
3.4 循环 while
3.4.1 无限循环
3.4.2 while 特殊用法 while read
3.4.3 循环 until(反的while)
3.5 循环与菜单 select
3.6 控制语句
3.6.1 循环控制语句 continue
3.6.2 循环控制语句 break
3.6.3 循环控制 shift 命令
4 函数 function
4.1 函数介绍
4.2.1 定义函数
4.2.2 查看函数
4.2.3 删除函数
4.3 函数调用
4.3.2 在脚本中定义及使用函数
4.4 函数返回值
4.5 环境函数
4.6 函数递归
5 其它脚本相关工具
5.1 信号捕捉 trap
5.2 创建临时文件 mktemp
6 数组 array
6.3 数组赋值
6.4 显示所有数组
6.5 引用数组
6.6 删除数组
6.8 关联数组
7 字符串处理
7.1 字符串切片
shell 脚本案例
1 显示指标(括CPU型号,内存大小,硬盘大小,操作系统版本)
2.编写脚本 backup.sh,可实现每日将 /etc/ 目录备份到 /backup/etcYYYY-mm-dd中
3.编写脚本 disk.sh,显示当前硬盘分区中空间利用率最大的值
4.编写脚本 links.sh,显示正连接本主机的每个远程主机的IPv4地址和连接数,并按连接数从大到小 排 序
一个shell脚本文件中主要包含以下内容
各种系统命令的组合
数据存储:变量、数组
表达式:a + b
控制语句:if
格式要求:首行shebang机制(#!)
#!/bin/bash #!/usr/bin/python #!/usr/bin/perl #!/usr/bin/ruby #!/usr/bin/lua
有的时候被启用有的时候不被启用
一般要注明作者,创建(修改)时间,文件名,版本号,该程序的功能及作用,目地,版权信息,作者联系 方式等
[root@bogon test.dir]# cat ~/.vimar cat: /root/.vimar: No such file or directory [root@bogon test.dir]# cat ~/.vimrc set nu set ts=4 autocmd BufNewFile *.sh exec ":call SetTitle()" func SetTitle() if expand("%:e") == 'sh' call setline(1,"#!/bin/bash") call setline(2,"#") call setline(3,"#****************************************************") call setline(4,"#Author: caojidong") call setline(5,"#QQ: 1549396190") call setline(6,"#Date: ".strftime("%Y-%m-%d")) call setline(7,"#FileName: ".expand("%")) call setline(8,"#cell-phone number: 13739548267") call setline(9,"#Description: test") call setline(10,"#Copyright(C): ".strftime("%Y")." All right") call setline(11,"#***************************************************") endif endfunc
[root@bogon test.dir]# ./1.test.sh #./sh,就是会去使用脚本中声明的第一行的解释器来解释脚本的内容 hello word caojidong [root@bogon test.dir]# . 1.test.sh hello word #在当前进程中执行 caojidong [root@bogon test.dir]# bash 1.test.sh hello word caojidong [root@bogon test.dir]# sh 1.test.sh #使用sh install.sh 如果这个脚本文件当前用户没有执行的权限也是能够执行的 hello word caojidong [root@bogon test.dir]# /tmp/test.dir/1.test.sh hello word caojidong
借鉴别人写的挺好的文章: https://blog.csdn.net/weixin_37569048/article/details/97764626?utm_medium=distribute.pc_relevant.none-task-blog-2defaultbaidujs_title~default-1.no_search_link&spm=1001.2101.3001.4242 ———————————————— 版权声明:本文为CSDN博主「如梦@_@」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。 原文链接:https://blog.csdn.net/weixin_43726471/article/details/120800757
瞬间启动子shell :用括号表示。
echo $BASHPID;( echo $BASHPID; sleep 300; )
本地执行远程脚本
[root@rocky86 ~]# curl http://10.0.0.157/test.sh -s | bash hello, world Hello, world! [root@rocky86 ~]# curl http://10.0.0.157/test.sh 2>/dev/null | bash hello, world Hello, world! [root@rocky86 ~]# wget -qO - http://10.0.0.157/test.sh | bash hello, world Hello, world!
curl和wget的区别和使用
1.下载文件
curl -O http://man.linuxde.net/text.iso #O大写,不用O只是打印内容不会下载 wget http://www.linuxde.net/text.iso #不用参数,直接下载文件
2.下载文件并重命名
curl -o rename.iso http://man.linuxde.net/text.iso #o小写 wget -O rename.zip http://www.linuxde.net/text.iso #O大写
3.断点续传
curl -O -C -URL http://man.linuxde.net/text.iso #C大写 wget -c http://www.linuxde.net/text.iso #c小写
4.限速下载
curl --limit-rate 50k -O http://man.linuxde.net/text.iso wget --limit-rate=50k http://www.linuxde.net/text.iso
5.显示响应头部信息
curl -I http://man.linuxde.net/text.iso wget --server-response http://www.linuxde.net/test.iso
6.wget利器--打包下载网站
wget --mirror -p --convert-links -P /var/www/html http://man.linuxde.net/
在远程主机运行(本地脚本)
[root@rocky86 ~]# cat test2.sh #!/bin/bash # #**************************************************** #Author: jose #QQ: 123456 #Date: 2022-08-16 #FileName: test2.sh #URL: http://www.magedu.com #Description: test #Copyright(C): 2022 All right #*************************************************** hostname -I #本地执行 [root@rocky86 ~]# bash test2.sh 10.0.0.150 #远程主机上执行 [root@rocky86 ~]# ssh [email protected] /bin/bash < test2.sh [email protected]'s password: 10.0.0.157
语法错误:会导致后续的命令不继续执行,可以用 bash -n 检查错误,提示的出错行数不一定是准 确的
命令错误:默认后续的命令还会继续执行,用 bash -n 无法检查出来 ,可以使用 bash -x 进行观察
逻辑错误:只能使用 bash -x 进行观察
此选项只能检测脚本中的语法错误,不能检测命令错误,也不会执行脚本
bash -n test.sh #bash -n 脚本名称
逐行输出命令,并输出执行结果
bash -x test.sh #bash -x 脚本名称
变量数据类型:
字符 数值:整型、浮点型,bash 不支持浮点数 布尔 指针 结构体
静态和动态语言
静态编译语言:使用变量前,先声明变量类型,之后类型不能改变,在编译时检查,如:java,c 动态编译语言:不用事先声明,可随时改变类型,如:bash,Python
强类型和弱类型语言
强类型语言:不同类型数据操作,必须经过强制转换才同一类型才能运算,如: java , c# , python 弱类型语言:语言的运行时会隐式做数据类型转换。无须指定类型,默认均为字符型;参与运算会 自动进行隐式类型转换;变量无须事先定义可直接调用,如:bash ,php,javascript
命名要求
区分大小写
不能使程序中的保留字和内置变量:如:if, for
只能使用数字、字母及下划线,且不能以数字开头,注意:不支持短横线 “ - ”,和主机名相反
#主机名只允许含ascii字符里的数字和字母,-和. 。其余的都不允许。
运行shell时,会同时存在三种变量:
变量的生效范围等标准划分变量类型
1、局部变量:局部变量在脚本或命令中定义,仅在当前shell实例中有效,其他shell启动的程序不能访问局部变量。
【小写:局部变量小写 函数名小写
大驼峰StudentFirstName,由多个单词组成,且每个单词的首字母是大写,其它小写
小驼峰studentFirstName ,由多个单词组成,第一个单词的首字母小写,后续每个单词的首字母 是 大写,其它小写】
2、环境变量:所有的程序,包括shell启动的程序,都能访问环境变量,有些程序需要环境变量来保证其正常运行,必要的时候shell脚本也可以定义环境变量。
【大写】
3、shell变量:shell变量是由shell程序设置的特殊变量,shell变量中有一部分是环境变量,有一部分是局部变量,这些变量保证了shell的正常运行。
1.2.2.1 赋值
value 可以是以下多种形式
name='root' #直接字串 name="$USER" #变量引用 name=`COMMAND` #命令引用 name=$(COMMAND) #命令引用
注意:变量赋值是临时生效,当退出终端后,变量会自动删除,无法持久保存,脚本中的变量会随着脚 本结束,也会自动删除
#变量保存、变量永久保存方法、变量永久保存路径
在/etc/profile文件中添加变量【对所有用户生效(永久的)】 [root@bogon ~]# vim /etc/profile 注:修改文件后要想马上生效还要运行$ source /home/guok/.bash_profile不然只能在下次重进此用户时生效。
1.2.2.2 引用
$name ${name}
弱引用和强引用 "$name" 弱引用,其中的变量引用会被替换为变量值 '$name' 强引用,其中的变量引用不会被替换为变量值,而保持原字符串
变量的间接赋值和引用(变量和变量引用)
[root@centos8 ~]#TITLE=cto [root@centos8 ~]#NAME=wang [root@centos8 ~]#TITLE=$NAME [root@centos8 ~]#echo $NAME wang [root@centos8 ~]#echo $TITLE wang [root@centos8 ~]#NAME=mage [root@centos8 ~]#echo $NAME mage [root@centos8 ~]#echo $TITLE wang
变量追加值
[root@centos8 ~]#TITLE=CTO [root@centos8 ~]#TITLE+=:wang [root@centos8 ~]#echo $TITLE CTO:wang
利用变量实现动态命令
[root@centos8 ~]#CMD=hostname [root@centos8 ~]#$CMD centos8.magedu.com
定义bash环境的用户文件是:.bashrc &bash_profile
使用echo命令查看单个环境变量。例如:
root@bogon ~]# echo $PATH /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin
使用env查看所有环境变量。例如:
[root@bogon ~]# env
查看指定进程的环境变量
cat /proc/$PID/environ #新指定的不输出
export命令定义变量
使用set查看所有本地定义的环境变量。
unset可以删除指定的环境变量。
[root@bogon test.dir]# export mage="66666666handsome" [root@bogon test.dir]# set | grep mage _=mage mage=66666666handsome [root@bogon test.dir]# unset mage [root@bogon test.dir]# echo "$mage"
变量赋值:
#声明并赋值 export name=VALUE declare -x name=VALUE #或者分两步实现 name=VALUE export name
declare 声明变量用法:
declare -x 声明环境变量export declare -r 声明只读变量readonly declare -i 声明整数int
bash内建的环境变量
PATH SHELL USER UID HOME PWD SHLVL #shell的嵌套层数,即深度 LANG MAIL HOSTNAME HISTSIZE _ #下划线,表示前一命令的最后一个参数
只读变量:只能声明定义,但后续不能修改和删除,即常量 声明只读变量:
readonly name declare -r name
readonly [-p] declare -r
[root@centos8 ~]#readonly PI=3.14159 [root@centos8 ~]#echo $PI 3.14159 [root@centos8 ~]#PI=3.14 -bash: PI: readonly variable [root@centos8 ~]#unset PI -bash: unset: PI: cannot unset: readonly variable [root@centos8 ~]#echo $PI 3.14159 [root@centos8 ~]#exit logout Connection closed by foreign host. Disconnected from remote host(10.0.0.8) at 14:27:04. Type `help' to learn how to use Xshell prompt. [c:\~]$ Reconnecting in 1 seconds. Press any key to exit local shell. . Connecting to 10.0.0.8:22... Connection established. To escape to local shell, press 'Ctrl+Alt+]'. WARNING! The remote SSH server rejected X11 forwarding request. Last login: Wed Apr 1 13:51:28 2020 from 10.0.0.1 [root@centos8 ~]#echo $PI [root@centos8 ~]#
$1,$2,... #对应第1个、第2个等参数,shift [n]换位置 $0 #命令本身,包括路径 $* #传递给脚本的所有参数,全部参数合为一个字符串 $@ #传递给脚本的所有参数,每个参数为独立字符串 $# #传递给脚本的参数的个数 #注意:$@ $* 只在被双引号包起来的时候才会有差异
清空所有位置变量
[root@centos8 ~]#cat /data/scripts/arg.sh #!/bin/bash # #**************************************************** #Author: jose #QQ: 123456 #Date: 2022-08-17 #FileName: arg.sh #URL: http://www.magedu.com #Description: test #Copyright(C): 2022 All right #*************************************************** echo "1st arg is $1" echo "2st arg is $2" echo "3st arg is $3" echo "10st arg is ${10}" echo "11st arg is ${11}" echo "The number of arg is $#" echo "All args are $*" echo "All args are $@" echo "The scriptname is `basename $0`" [root@centos8 ~]#bash /data/scripts/arg.sh {a..z} 1st arg is a 2st arg is b 3st arg is c 10st arg is j 11st arg is k The number of arg is 26 All args are a b c d e f g h i j k l m n o p q r s t u v w x y z All args are a b c d e f g h i j k l m n o p q r s t u v w x y z The scriptname is arg.sh
范例:删库跑路之命令rm的安全实现
rm=/tmp/test.dir/2.rm.test.sh [root@centos8 ~]#cat /data/scripts/rm.sh #!/bin/bash WARNING_COLOR="echo -e \E[1;31m" END="\E[0m" DIR=/tmp/`date +%F_%H-%M-%S` mkdir $DIR mv $* $DIR ${WARNING_COLOR}Move $* to $DIR $END [root@centos8 ~]#chmod a+x /data/scripts/rm.sh [root@centos8 ~]#alias rm='/data/scripts/rm.sh' #添加别名 [root@centos8 ~]#touch {1..10}.txt [root@centos8 ~]#rm *.txt Move 10.txt 1.txt 2.txt 3.txt 4.txt 5.txt 6.txt 7.txt 8.txt 9.txt to /tmp/2020- 04-01_15-15-28
范例:$*和$@的区别
[root@centos8 scripts]#cat f1.sh #!/bin/bash echo "f1.sh:all args are $@" echo "f1.sh:all args are $*" ./file.sh "$*" [root@centos8 scripts]#cat f2.sh #!/bin/bash echo "f2.sh:all args are $@" echo "f2.sh:all args are $*" ./file.sh "$@" [root@centos8 scripts]#cat file.sh #!/bin/bash echo "file.sh:1st arg is $1" [root@centos8 scripts]#./f1.sh a b c f1.sh:all args are a b c f1.sh:all args are a b c 范例: 利用软链接实现同一个脚本不同功能 2.7.9 退出状态码变量 当我们浏览网页时,有时会看到下图所显示的数字,表示网页的错误信息,我们称为状态码,在shell脚 本中也有相似的技术表示程序执行的相应状态。 file.sh:1st arg is a b c [root@centos8 scripts]#./f2.sh a b c f2.sh:all args are a b c f2.sh:all args are a b c file.sh:1st arg is a
范例: 利用软链接实现同一个脚本不同功能
[root@centos8 ~]#cat test.sh #!/bin/bash #******************************************************************** echo $0 [root@centos8 ~]#ln -s test.sh a.sh # a.sh 是连接文件(linkname) [root@centos8 ~]#ln -s test.sh b.sh [root@centos8 ~]#./a.sh ./a.sh [root@centos8 ~]#./b.sh ./b.sh
进程执行后,将使用变量 $? 保存状态码的相关数字,不同的值反应成功或失败,$?取值范例 0-255
$? #0代表成功,1-255代表失败 [root@centos8 ~]#curl -fs http://www.wangxiaochun.com >/dev/null [root@centos8 ~]#echo $? 0
用户可以在脚本中使用以下命令自定义退出状态码
exit [n]
注意:
脚本中一旦遇到exit命令,脚本会立即终止;终止退出状态取决于exit命令后面的数字
如果exit后面无数字,终止退出状态取决于exit命令前面命令执行结果
如果没有exit命令, 即未给脚本指定退出状态码,整个脚本的退出状态码取决于脚本中执行的最后一 条命令的状态码
展开命令执行顺序
把命令行分成单个命令词 展开别名 展开大括号的声明{} 展开波浪符声明 ~ 命令替换$() 和 `` 再次把命令行分成命令词 展开文件通配符*、?、[abc]等等 准备I/0重导向 <、> 运行命令
防止扩展
\ #反斜线 会使随后的字符按原意解释
[root@centos8 ~]#echo Your cost: \$5.00 Your cost: $5.00 [root@rocky8 ~]#echo "The book's price is \$10" The book's price is $10