iOS高级进阶系列之-Shell语言(上)Shell基础语法

2,069 阅读9分钟

系列文章:OC底层原理系列OC基础知识系列Swift底层探索系列iOS高级进阶系列

前言

之前文章写的都会说到脚本,这篇我们就好好的聊聊shell脚本,聊聊shell的语法,至于写一些脚本执行一些功能,我这边也会写一些大家经常用到的功能吧!

shell语法

Shell简介

  • Shell:一种命令行解释器,是Unix操作系统下最传统人机接口
  • Shell脚本:解释执行的,不需要编译,和大部分的编程语言很相似,也有基本的变量流程控制语句 平时使用Shell有两种方式:
  • 1.输入命令执行,这种方式称为交互式(Interactive)
  • 2.批处理(Batch)方式,用户事先写好Shell脚本文件,然后顺序执行脚本中的命令。 目前Shell除了默认的bash,现在macOS中,默认的Shell变成了zsh。这是一种由Paul Falstad1990年开发的。它是一个Bourne式Shell,它使用bashprevious shell的特性,并添加了更多的特性:
  • 1.拼写检查功能
  • 2.内置的编程特性
  • 3.友好的交互 image.png 与此同时,macOS还提供了很多其他种类的Shell: image.png

.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:
    • 建议仍然将配置选项放到~/.bashrc~/.bash_profile通过source调用,最后在~/.zshrc中source调用~/.bash_profile。 常用命令参考:Linux命令搜索Linux命令

主要语法介绍

注释

image.png

特殊符号(重点)

  • 1.双引号 " ":用于包含一组字符串,在双引号中,除了 "$"、"\"、" ‘ (反引号)"有特殊含义外,其余字符(如换行符、回车符等)没有特殊含义
  • 2.单引号 ' ':单引号的功能与双引号类似不过单引号中的所有字符都没有特殊含义
  • 3.反引号 ’ ‘:反引号的功能是命令替换,在反引号‘ ’中内容通常是命令行,程序会优先执行反引号中的内容,并使用运行结果替换掉反引号处的内容
  • image.png

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.大多数命令都不接受标准输入作为参数,只能直接在命令行输入参数,这导致无法用管道命令传递参数
  • 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:执行指令后,会先显示该指令及所下的参数
  • 8.declare/typeset [-aixrp] 变量
    • -a 将变量定义成数组
    • -i 将变量定义成整数
    • -x 将变量定义成环境变量
    • -r 将变量定义成readonly
    • -p:显示变量定义的方式和值
    • +:取消变量属性,但是 +a 和 +r 无效,无法删除数组和只读属性,可以使用unset删除数组,但是 unset 不能删除只读变量
  • 9.local关键字,用来在作用域内创建变量。出来作用域被销毁
  • 10.export为shell变量函数设置导出属性,成为环境变量。无法对未定义的函数添加导出属性。同时,重要的一点是,export的效力仅及于该次登陆操作。注销或者重新开一个窗口,export命令给出的环境变量都不存在了
    • -f:代表[变量名称]为函数名称
    • -n:删除变量的导出属性。变量实际上并未删除,只是不会输出到后续指令的执行环境中
    • -p:显示全部拥有导出属性的变量
    • -pf:显示全部拥有导出属性的函数
    • -nf:删除函数的导出属性
    • --:在它之后的选项无效
  • 11.通配符
    • *:匹配任意字符串,包括空字符串,不包含对“/”字符的匹配
    • ?:匹配任意单个字符,不能匹配“/”字符
    • [abc]:匹配“a”或者“b”或者“c”字符
    • [^abc]:不匹配“a”或者“b”或者“c”字符
    • [a-z]:匹配26个英文小写字符中任意一个
  • 12.用set命令可以查看所有的变量unset var命令可以清除变量var,var相当于没有定义过。readonly var可以把var变为只读变量,定义之后不能对var进行任何更改

参数扩展

    1. 间接参数扩展
    • ${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 语句image.png image.png
  • []:判断符号,两个等号一个等号,效果类似
    • 1.中括号里面的每个组件都需要空格分隔
    • 2.中括号的变量使用双引号
    • 3.中括号的常量使用单引号或双引号

test命令测试

  • 1.test n1 -eq n2:
    • -eq:相等
    • -ne:不等
    • -gt:大于
    • -lt:小于
    • -ge:大于等于
    • -le:小于等于
  • 2.字符串判断
    • -z string:判断string是否为0,为空,则为true
    • -n string:判断string是否非0,为空,则为false
    • string1 = string2:字符串是否相等相等为true
    • string1 != string2:字符串是否不等相等为false
  • 3.多重条件判断
    • -a:两个条件同时成立,为true
    • -o:两个条件任何一个成立,为true
    • !:反向
  • 4.文件类型判断
    • -e:文件名是否存在
    • -f:该文件名是否存在且是否为文件
    • -d:该名称是否存在且为目录
    • -L:该名称是否存在且是否为链接文件
  • 5.文件权限检测
    • -r:是否存在是否有可读权限
    • -w:是否存在是否有可写权限
    • -x:是否存在是否有可执行权限
    • -s:是否存在且为非空白文件
  • 6.两文件比较
    • -nt 文件1是否比文件2新
    • -ot 文件1是否比文件2旧
    • -ef 文件1和文件2是否为同一个文件

循环

image.png

写到最后

这篇文章是自己对shell语言语法的一个总结,为后面写shell脚本做准备,下篇的shell脚本中,这篇介绍过的语法奖不再解释,有什么疑问可以在下面留言,也希望大家多多交流,点赞!