前言
之前文章写的都会说到脚本,这篇我们就好好的聊聊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脚本中,这篇介绍过的语法奖不再解释,有什么疑问可以在下面留言,也希望大家多多交流,点赞!