前言
之前文章写的都会说到脚本,这篇我们就好好的聊聊shell脚本,聊聊shell的语法,至于写一些脚本执行一些功能,我这边也会写一些大家经常用到的功能吧!
shell语法
Shell简介
- Shell:一种
命令行解释器
,是Unix操作系统下最传统
的人机接口
。 - Shell脚本:
解释执行
的,不需要编译
,和大部分的编程语言
很相似,也有基本的变量
和流程控制语句
平时使用Shell有两种方式: - 1.
输入命令
,执行
,这种方式称为交互式(Interactive)
; - 2.
批处理(Batch)方式
,用户事先写好Shell脚本文件,然后顺序执行脚本中的命令。 目前Shell除了默认的bash
,现在macOS中,默认的Shell变成了zsh
。这是一种由Paul Falstad
于1990年开发
的。它是一个Bourne式Shell
,它使用bash
和previous shell
的特性,并添加了更多的特性: - 1.
拼写检查功能
- 2.
内置的编程特性
- 3.
友好的交互
与此同时,macOS还提供了很多其他种类的Shell:
.bashrc、.bash_profile和.zshrc作用与区别
在使用命令行工具时,我们可能会遇到一些教程,可能需要你把一些配置写入到.bashrc、.bash_profile
或者.zshrc
等。那么这几个文件到底有什么作用和区别?
首先,从文件名称判断.bashrc、.bash_profile
是给Bash来使用
的。而.zshrc是给zsh来使用
的。
交互式登录和非登录Shell
当调用Shell时,Shell从一组启动文件
中读取信息
并执行命令
。读取什么文件
就取决
于Shell
是作为交互式登录
还是非登录调用
。换言之,Shell分
为交互式
的或非交互式
的:
交互式Shell
是读取
和写入
到用户终端的Shell程序
,用户在终端上输入命令
,并在回车后立即执行
。非交互式Shell
是与终端不相关的Shell程序
,例如执行脚本时。 配置建议:- 1.bash:
- 将
配置选项放到~/.bashrc
中,然后在~/.bash_profile
中通过source调用
。
- 将
- 2.zsh:
主要语法介绍
注释
特殊符号(重点)
- 1.
双引号 " "
:用于包含一组字符串
,在双引号中
,除了"$"、"\"、" ‘ (反引号)"
有特殊含义外,其余字符(如换行符、回车符等)没有特殊含义
。 - 2.
单引号 ' '
:单引号的功能与双引号类似
,不过单引号
中的所有字符都没有特殊含义
。 - 3.
反引号 ’ ‘
:反引号的功能是命令替换
,在反引号‘ ’中
的内容通常是命令行
,程序会优先执行反引号中的内容
,并使用运行结果替换掉反引号处的内容
。
dollar符单独显示有问题
- 8.
小括号 ( )
:用来定义一个数组变量
。 - 9.
双小括号 (( ))
:双小括号命令允许在比较过程中使用高级数学表达式
。 - 10.
中括号 [ ]
:单个
的中括号的功能与test命令一样
,都是用作条件测试。 - 11.
双中括号 [[ ]]
:双中括号提供了针对字符串比较的高级特性
,使用双中括号 [[ ]] 进行字符串比较时
,可以把右边的项看做一个模式
,故而可以在 [[ ]] 中使用正则表达式
。 - 12.
大括号 { }
:大括号用于括起一个语句块
。 - 13.
冒号(:)
作为内建命令
:占位符、参数扩展和重定向
。注意⚠️:单引号与双引号
,括号一定要成对
。 - 14.
expr命令
是一款表达式计算工具
,使用它完成表达式
的求值操作
。 - 15.
eval
会对后面
的cmdLine进行两遍扫描
,如果第一遍扫描
后,cmdLine是个普通命令
,则执行此命令
;如果cmdLine中含有变量
的间接引用
,则保证间接引用的语义
。
输出
- 1.
标准输入(stdin)
:代码为0,使用<或<<
- 2.
标准输出(stdout)
:代码为1,使用>或>>
- 3.
标准错误输出(stderr)
:代码为2,使用2>或2>>
- 4.
1>
:以覆盖
的方式将正确
的数据输出
到指定到文件
或设备
- 5.
1>>
:以累加
到方式将正确
的数据输出到指定到文件
或者设备
上 - 6.
2>
:以覆盖
的方式将错误
的数据输出到指定到文件
或设备
- 7.
2>>
:以累加
的方式将错误
的数据输出到指定到文件
或设备
- 8.
2>/dev/null
:将错误到数据丢弃
,只显示正确
的数据
- 9.
2>&1
或者&>
:将正确
的数据
和错误
的数据写入同一个文件
- 10.
1>&2
:正确返回值传递给2输出通道
,&2
表示2输出通道
- 11.
2>&1
:错误返回值传递给1输出通道
, 同样&1
表示1输出通道
- 12.
cmd
:cmd不考虑命令相关性
,连续执行
- 13.当前一个命令
执行成功
会回传一个$?=0的值
- 14.
cmd1 && cmd2
:如果第一个命令
的$?为0
,则执行第二个命令
- 15.
cmd1 || cmd2
:如果第一个命令
的$?为0
,则不执行第二个命令
。否则执行第二个命令
- 16.
|
:管道仅能处理前面一个命令传来
的正确信息
,将正确信息作为stdin传给下一个命令
- 1.管道命令
只处理前一个命令正确输出
,不处理错误输出
- 2.管道命令
右边命令
,必须能够接收标准输入流
命令才行 - 3.大多数命令都不接受标准输入作为参数,只能直接在命令行输入参数,这导致无法用管道命令传递参数
- 1.管道命令
- 17.
-
:减号
在一些命令中表示从标准输入(stdin)中获取内容
- 18.
xargs
:是将标准输入转为命令行参数
运行
运行方式
- 1.
sh
:使用$ sh script.sh执行脚本
时,当前shell是父进程
,生成一个子shell进程
,在子shell中执行脚本
。脚本执行完毕
,退出子shell
,回到当前shell
。$ ./script.sh
与$ sh script.sh等效
。也叫fork方式
- 2.
source
:使用$ source script.sh方式
,在当前上下文中执行脚本
,不会生成新的进程
。脚本执行完毕
,回到当前shell
。$ . script.sh
与$ source script.sh
等效。不需要有"执行权限" - 3.
exec方式
:使用exec ./scriptsh方式
,会用command进程
替换当前shell进程
,并且保持PID不变
。执行完毕
,直接退出
,不回到之前的shell环境
是否需要权限
- 1.
sh /bash/zsh不需要有"执行权限"
- 2.
./script.sh需要有"执行权限"
- 3.
source script.sh不需要有"执行权限"
- 4.
exec需要有"执行权限"
变量定义
- 1.
Shell变量默认为字符串
。shell不关心这个串是什么含义
- 2.Shell默认的
数值运算是整数类型
。所以若要进行数学运算
,必须使用一些命令
例如declare、expr、双括号等 - 3.Shell变量可分为两类:
局部变量
:只在创建它们的shell中可用
。在函数内定义,函数执行后就被删除
环境变量
:可以在创建它们的shell及其派生出来的任意子进程中使用
。在整个脚本执行期间,只要没有被删除就一直存在
- 4.
定义规则
:变量名必须以字母或下划线字符开头
。其余的字符可以是字母、数字(0~9)或下划线字符。任何其他的字符都标志着变量名的终止
。小写敏感
- 5.给变量赋值时,
等号周围不能有任何空白符
- 6.通常
大写字符为系统默认变量
。个人习惯 - 7.set:查看所有变量(含环境变量与自定义变量),以及
设置shell变量的新变量值
- -a:
标示已修改的变量,以供输出至环境变量
- -b:
使被中止的后台程序立刻回报执行状态
- -e:
若指令传回值不等于0,则立即退出shell
- -f:
取消使用通配符
- -h:
自动记录函数的所在位置
- -H Shell:
可利用"!"加<指令编号>的方式来执行history中记录的指令
- -k:
指令所给的参数都会被视为此指令的环境变量
- -l:
记录for循环的变量名称
- -m:
使用监视模式
- -n:
只读取指令,而不实际执行
- -p:
启动优先顺序模式
- -P:
启动-P参数后,执行指令时,会以实际的文件或目录来取代符号连接
- -t:
执行完随后的指令,即退出shell
- -u:
当执行时使用到未定义过的变量,则显示错误信息
- -v:
显示shell所读取的输入值
- -x:
执行指令后,会先显示该指令及所下的参数
- -a:
- 8.declare/typeset [-aixrp] 变量
- -a
将变量定义成数组
- -i
将变量定义成整数
- -x
将变量定义成环境变量
- -r
将变量定义成readonly
- -p:
显示变量定义的方式和值
- +:
取消变量属性
,但是+a 和 +r 无效
,无法删除数组和只读属性,可以使用unset删除数组
,但是unset 不能删除只读变量
- -a
- 9.
local关键字
,用来在作用域内创建变量。出来作用域被销毁
- 10.
export为shell变量
或函数设置导出属性
,成为环境变量。无法对未定义的函数添加导出属性。同时,重要的一点是,export的效力仅及于该次登陆操作
。注销或者重新开一个窗口,export命令给出的环境变量都不存在了- -f:
代表[变量名称]为函数名称
- -n:
删除变量的导出属性。变量实际上并未删除,只是不会输出到后续指令的执行环境中
- -p:
显示全部拥有导出属性的变量
- -pf:
显示全部拥有导出属性的函数
- -nf:
删除函数的导出属性
- --:
在它之后的选项无效
- -f:
- 11.通配符
- *:
匹配任意字符串,包括空字符串,不包含对“/”字符的匹配
- ?:
匹配任意单个字符,不能匹配“/”字符
- [abc]:
匹配“a”或者“b”或者“c”字符
- [^abc]:
不匹配“a”或者“b”或者“c”字符
- [a-z]:
匹配26个英文小写字符中任意一个
- *:
- 12.用
set命令
可以查看所有的变量
,unset var命令
可以清除变量var
,var相当于没有定义过。readonly var
可以把var变为只读变量
,定义之后不能对var进行任何更改
参数扩展
-
- 间接参数扩展
- ${parameter-string}:
当parameter未设置则替换成string,不更改parameter值。否则,不做处理
- ${parameter=string}:
当parameter未设置则替换成string,更改parameter值。否则,不做处理
- ${parameter?string}:
parameter没有设置,则把string输出到标准错误中。否则,不做处理
- ${parameter+string}:
当parameter为空的时替换成string。否则,不做处理
- ⚠️
${!parameter},zsh不支持
- 2.冒号后面跟 等号,加号,减号,问号(⚠️不能有空格)
- ${parameter:-string}:当parameter未设置或者为空则替换成string,不更改parameter值
- ${parameter:=string}:当parameter未设置或者为空则替换成string,更改parameter值
- ${parameter:?string}:若变量parameter不为空,则使用变量parameter的值。若为空,则把string输出到标准错误中,并从脚本中退出。
- ${parameter:+string}:当parameter不为空的时替换成string。若为空时则不替换或者说是替换空值
- 3.子串扩展:
${parameter:offset}
和${parameter:offset:length}
。从offset位置开始截取长度
为length的子串,如果没有提供length,则是从offset开始到结尾offset可以是负值
,且必须与冒号有间隔
或者用()包裹
。开始位置是从字符串末尾开始算起,然后取长度为length的子串
。例如,-1代表是从最后一个字符开始parameter是@
,也就是所有的位置参数
时,offset必须从1开始
- 4.替换:
${parameter/pattern/string}
、${parameter//pattern/string}
、${parameter/pattern}和${parameter//pattern}
。大小写敏感。string为空时,则相当于将匹配的子串删除
。 parameter之后如果是/
,则只匹配遇到的第一个子串
;parameter之后如果是//
,则匹配所有的子串
- 5.删除:
${parameter#pattern}
、${parameter##pattern}
、${parameter%pattern}
和${parameter%%pattern}
#是去掉左边
,% 是去掉右边
。单一符号是最小匹配﹔两个符号是最大匹配
- 6.参数长度:${#parameter}
test与判断
多分支语句判断
- 除最后一个分支外(这个分支可以是普通分支,也可以是*)分支),其它的
每个分支都必须以;;结尾
,;;代表一个分支的结束
,不写
的话会有语法错误
。最后一个分支
可以写;;
,也可以不写
,因为无论如何,执行到 esac
都会结束整个 case in 语句
。 - []:判断符号,
两个等号
和一个等号
,效果类似- 1.中括号里面的
每个组件都需要空格分隔
- 2.中
括号的变量
,使用双引号
- 3.中
括号的常量
,使用单引号或双引号
- 1.中括号里面的
test命令测试
- 1.test n1 -eq n2:
- -eq:
相等
- -ne:
不等
- -gt:
大于
- -lt:
小于
- -ge:
大于等于
- -le:
小于等于
- -eq:
- 2.字符串判断
- -z string:
判断string是否为0,为空,则为true
- -n string:
判断string是否非0,为空,则为false
- string1 = string2:
字符串是否相等
,相等为true
- string1 != string2:
字符串是否不等
,相等为false
- -z string:
- 3.多重条件判断
- -a:
两个条件同时成立,为true
- -o:
两个条件任何一个成立,为true
- !:
反向
- -a:
- 4.文件类型判断
- -e:
文件名是否存在
- -f:
该文件名是否存在且是否为文件
- -d:
该名称是否存在且为目录
- -L:
该名称是否存在且是否为链接文件
- -e:
- 5.文件权限检测
- -r:
是否存在是否有可读权限
- -w:
是否存在是否有可写权限
- -x:
是否存在是否有可执行权限
- -s:
是否存在且为非空白文件
- -r:
- 6.两文件比较
- -nt
文件1是否比文件2新
- -ot
文件1是否比文件2旧
- -ef
文件1和文件2是否为同一个文件
- -nt
循环
写到最后
这篇文章是自己对shell语言语法
的一个总结,为后面写shell脚本做准备
,下篇的shell脚本中,这篇介绍过的语法奖不再解释,有什么疑问可以在下面留言,也希望大家多多交流,点赞!