【Linux】【笔记】Shell从入门到精通

认识Shell编程

  1. 比较流行的shell程序都是bash
  2. shell是套在内核外面的一层外壳,向普通用户隐藏了许多关于系统内核的细节
  3. 在UNIX系统中,shell即使用户交互的界面,也是控制系统的脚本语言
  4. Bash是绝大多数Linux发行版的默认shell
  5. 当shell期待用户下一步输入时,shell提示符会从#变成>
  6. shell脚本以#!开头的一行代表它后面的那个参数时用来执行本文件的程序
  7. #!后面跟的是绝对路径,程序会搜索对应的路径,然后用创建对应的解释器进程来解释并执行当前脚本的语句
  8. 如果没有#! 我们也可以通过source来执行,这样就是在当前shell执行
  9. 我们给shell脚本传递参数,如果参数有空格,需要用""包起来
  10. 注释有两种,一种是#,另外一种是用用:配合here document来使用
  11. Linux每个命令都有一个退出状态码,成功是0,我们也可以用exit语句指定

Shell编程环境搭建

  1. bash的主要配置文件有5个,有每个用户的,也有全局的
  2. 为了简化命令,可以给命令设置别名,别名优先级要高于原始命令

变量和引用

  1. shell变量是弱类型,不需要显式声明数据类型
  2. shell变量会统一按照字符串存储,但是可以进行整数的加减等
  3. 如果一定要控制变量类型,可以使用declare来声明变量,这个属性也可以取消
  4. Shell语言中的三种引号非常重要
    • 单引号
    • 双引号
    • 反括号 反括号在双引号中出现会被解释成命令
  5. 注意,在方法内部定义的变量也是全局变量,作用一直到Shell脚本结束或被显式的删除
  6. 使用local定义局部变量,方法结束就没了
  7. 取变量的值用$符号
  8. 如果我们想输出脚本名称,或者上个命令退出状态码,可以用系统变量
  9. 环境变量是所有Shell程序都可以使用的变量,可以使用set列出环境变量
    • PATH 命令搜索路径
    • HOME 用户主目录的路径名
  10. 引用
    • 双引号 除了美元符号,单引号,反引号,反斜线外都保持字面意义
    • 单引号 全都保持字面意义
    • 反引号 里面解析成shell命令

条件测试和判断语句

  1. 条件为真,返回0
  2. 条件测试语法有test和[命令
  3. 使用方括号的时候一定要注意和参数保持一个空格
  4. 条件测试的运算符,比如=号两边一定要有空格,有空格才和JAVA的==一样
  5. 整数之间的比较,一定要用-eq这类运算符,不要用=号和!=,这俩是字符串比较的
  6. 条件测试也可以测试文件是否存在,可读可写等
  7. ! 是逻辑非 -a是逻辑与 -o是逻辑或
  8. if后面可以是条件表达式,也可以是Shell命令
  9. 空命令:一定返回0
  10. exit 语句还可以带一个可选的参数,用来指定程序退出时的状态码,我们可以通过这个状态码传递给父进程信息
  11. case语句注意事项
    • 条件测试部分以右括号结束
    • 一对分号相当于break
    • 星号加右括号相当于default
  12. 运算符有
    • expr
    • $((…))和$[…] ,建议使用,因为它不需要对运算符和括号转义,可以采用松散或者紧凑的格式来书写表达式
  13. 使用 let 命令可以执行一个或者多个算术表达式,其中的变量名无需使用$符号
  14. shell也有自增和自减运算符,自增自减只能针对变量,不能对常量或表达式使用

循环结构

  1. FOR循环可以指定步长,可以用…来代表范围
for i in {1..100..2}
  1. FOR循环也可以使用字符串和命令
# 字符串
for day in {Mon Tue Wed Thu Fri Sat Sun}
# 命令
for file in $(ls)
  1. FOR循环如果没有IN,那么默认IN后面跟的是用户的调用参数
  2. 类C风格的FOR循环
for ((expression1;expression2;expression3))
for (( i=1;i<5;i++))
  1. 数组形式的FOR循环
 array=(Monday Tuesday Wednesday Thursday Friday Saturday Sunday) 
#通过 for 循环遍历数组元素
for day in ${array[*]}
  1. Until循环
until expression 
do 
 ... 
done
  1. while 循环语句
while expression 
do 
 ... 
done
  1. break N 表示跳出N层循环,默认是1层,continue也可以跟参数

函数

  1. 函数和SHELL脚本不同之处在于它不会创建新进程
  2. 函数可以有两种定义方式
function_name ()
function function_name ()
  1. 函数一定要在调用之前定义,调用时不用加(),函数调用函数也必须保证定义顺序
  2. 返回值很重要,return语句只能返回0-255的整数,如果不在这个范围,就会返回1
  3. 如果要突破return的限制,可以使用echo,echo的返回值并没有限制,通过它来写到标准输出
  4. 函数内部,如果没用local关键字,则也是全局变量
  5. SHELL脚本定义时,不需要指定参数,可以使用时直接传入,通过位置变量获取
  6. shift命令可以使脚本参数左移,左移之后左面的就被删除了,它会改变$#的值
  7. getopts可以处理复杂的入参
[hello@Git shell]$ bash test.sh -a hello
this is -a the arg is ! hello
[hello@Git shell]$ more test.sh 
#!/bin/bash
 
# 这个opt保存了我们存到OPTARG里面的变量名
while getopts "a:" opt; do
  case $opt in
    a)
      echo "this is -a the arg is ! $OPTARG" 
      ;;
    \?)
      echo "Invalid option: -$OPTARG" 
      ;;
  esac
done

getopts一共有两个参数,第一个是-a这样的选项,第二个参数是 hello这样的参数。

选项之间可以通过冒号:进行分隔,也可以直接相连接,:表示选项后面必须带有参数,如果没有可以不加实际值进行传递

getopts ahfvc: option表明选项a、h、f、v可以不加实际值进行传递,而选项c必须取值,值保存在$OPTARG

  1. 变量名可以通过!间接应用
var=name 
name=John

引用name的两种方式

${name} 
${!var}
  1. SEHLL脚本本质上不支持数组作为函数参数,但是我们可以使用变通的方式
#! /bin/bash

#定义函数
func()
	{
		echo "number of elements is $#."
		while test $# -gt 0 
		do
			echo "$1"
			shift
		done
	}
	#定义数组
	a=(a b "c d" e)
	#调用函数,注意这里的引号,它将c和d看成一个
	func "${a[@]}"

输出

number of elements is 4. 
a 
b 
c d 
e
  1. 函数库文件里面只有函数
  2. 载入库文件方法
# 注意,点号和filename之间有个空格,filename可以使绝对或相对路径
. filename

数组

  1. 定义数组有四种方式
# 直接使用下标,这种定义了1个,那么数组长度就是1
array[1]=one
# 使用declare -a
declare -a array 
array[0]=1
# 通过元素值集合定义数组
array=(1 2 3 4 5 6 7 8)
# 通过键值对定义数组
array=([1]=one [4]=four)
  1. 当我们只有数组名访问数组的时候,返回的是下标为0的元素的值
array=(1 2 3 4 5)
# 下面返回1
echo "${array}"
  1. 数组可以使用截断某一部分,也可以截断某个元素的某一部分
  2. 可以用unset来删除数组某个元素或者整个数组,删除后某个元素数组长度减1
  3. 数组可以复制或者连接
# 复制
newarray=("${array[@]}")
# 连接
("$array1[@]}" "${array2[@]}")
  1. 数组可以加载某个文件,文件的每一行构成数组的一个元素
content=(`cat "demo.txt"`) 
#通过循环输出数组内容
for s in "${content[@]}" 
do 
echo "$s" 
done

正则表达式

  1. 正则表达式的核心是元字符
  2. 正则表达式有
    • 基本正则表达式
    • 扩展正则表达式
    • Perl正则表达式
    • POSIX字符集

基本文本处理

  1. echo -n 不输出行尾换行符,在默认情况下,echo 命令在输出文本的末尾会自动追加一个换行符
  2. echo中支持转义字符,我们可以通过转义字符来定义输出格式
  3. echo中输出变量需要 ${变量}括起来
  4. echo后面跟反引号括起来的shell命令,可以将shell结果输出
  5. 文本的格式化输出主要有三种
  • 制表符,转义字符\t
  • 使用 fold 命令格式化行,功能是将超过指定宽度的文本行进行折叠处理,使得超过指定宽度的字符转到下一行输出
  • pr命令 转换成适合打印的格式
  • fmt命令 格式化段落
  1. sort可以对文本行进行排序,可以指定字段,分隔符,如果对数字排序则使用-n
  2. 统计文本行数主要有两种方式
  • grep -c
  • wc 这个命令也可以统计单词书,字符数等等
  1. cut命令可以用来选取文本列
  2. paste可以用来拼接文本列
  3. join命令可以以指定列来连接文本列,包括左连接,右连接等
  4. tr命令用来替换文件内容

流编辑

  1. sed 命令会从文件或者标准输入中一次读取一行数据,将其复制到缓冲区,然后读取
    命令行或者脚本的编辑子命令,对缓冲区中的文本行进行编辑。重复此过程,一直到所有
    的文本行都处理完毕
  2. sed命令适合编辑一个非常大的文本文件
  3. sed命令不会影响原始文件,处理结果我们可以重定向到硬盘
  4. sed的核心option
  • -n 这样sed命令就不会写到标准输出了
  1. sed命令的三种工作方式
  • 直接在命令行使用
sed [options] commands inputfile
  • 将sed命令写入sed脚本
sed [options] -f script inputfile
  • 在脚本中直接指定解释器
./scrpt inputfile

然后脚本第一行如下

#! /bin/sed
  1. 位置参数
  • 通过行号定位
  • 通过正则表达式定位
  1. 子命令p将缓冲区中的文本行执行输出操作
  2. sed常用的命令
  • 选择文本
sed -n '1,3p' students.txt
  • 替换文本,s子命令
  • 删除文本, d子命令
  • 追加文本, a子命令
  • 插入文本, i 子命令
  1. 组合命令 多个sed命令组合在一起来完成
  • 使用-e选项
  • 使用分号执行多个子命令
  • 对一个地址使用多个子命令
address { 
 command1
 command2 
 command3 
… 
}
  • sed 提供了-f 选项,通过这个选项,sed 命令可以从指定的脚本文件中读取子命令,然后对每个文本行依次执行各个子命令,其语法如下
sed -f script

文本处理利器awk命令

  1. 在绝大部分的 Linux 发行版中,默认安装的是 gawk, 即 GNU awk
  2. awk 是 Linux 以及 UNIX 环境中现有的功能最强大的数据处理工具
  3. 在许多 Linux 发行版中,/bin/awk 命令是/bin/gawk 命令的符号链接
  4. awk命令的基本语法
# actions 前面的左大括号需与 pattern 位于同一行中
awk pattern { actions }

pattern 和 actions 都是可选的,但是两者必须保证至少有一个。如果省略匹配模式 pattern,
则表示对所有的文本行执行 actions 所表示的操作;如果省略 actions,则表示将匹配成功的
行输出到屏幕

  1. awk 会自动逐行读取数据文件的所有文本行
  2. 执行awk的三种方式
  • 通过命令行执行awk
# 注意单引号,'program-text'是要执行的命令
awk 'program-text' datafile
  • 执行awk脚本
# 注意开头
#! /bin/awk -f

# awk 脚本中不能含有除 awk 语句之外的其他命令或者语句,例如 Shell 命令等
awk -f program-file file ..`
  • 可执行脚本文件
  1. awk匹配模式
  • 关系表达式,例如大于>、小于<或者等于==等
#打印第 2 列的成绩超过 80 的行
result='awk '$2 > 80 { print }' scores.txt'
  • 正则表达式
#输出以字符 T 开头的行
result='awk '/^T/ { print }' scores.txt'
  • 混合模式 支持使用逻辑运算符 &&、||或者!将多个表达式组合起来作为一个模式
  • 区间模式 就是两个行以及之间的内容
  • BEGIN模式 就相当于awk的一个前置处理
  • END模式 后置处理
  1. awk变量类型分为字符串和数值,awk会根据环境自动判断类型
  2. 系统内置变量
  • $0 记录变量,表示当前正在处理的记录
  • $n 字段变量,其中 n 为整数,且 n 大于 1。表示第 n 个字段的值
  • FS 字段分隔字符,默认值是空格或者制表符,可以在BEGIN中指定
  • RS 记录分隔符,默认值是换行符,可以在BEGIN中指定
  1. 运算符和表达式
  • 算术运算符
  • 赋值运算符
  • 条件运算符
  • 逻辑运算符
  • 关系运算符

…等等

  1. awk对也支持很多对字符串的函数,也提供了很多比如平方根等算数函数
  2. awk支持对数组
  • 数组下标不一定是整数
  • 数组可以遍历,但是按顺序遍历的条件是下标识连续的整数
  1. 支持for,if,continue等流程控制语句
  • 当遇到next时,awk 会继续读取下一行数据
  1. awk 程序的格式化输出主要有print,printf,sprintf()
  2. awk 的程序与 Shell 的交互
  • 管道,awk的管道和unix管道不是一个意思
  • system函数,这个局限性比较大

基本文本处理

  1. 命令输出文本echo

    • 多用于显示提示信息或者程序产生的数据
    • echo可以搭配-e和制表符来制作表格
    • echo默认自带一个换行符
  2. 文本的格式化输出

    • 可以对文本的输出格式更加细致的控制
    • 制表符\t搭配echo
    • fold命令可以指定换行的宽度
    • fmt可以格式化段落,可以完全替代fold
    • rev反转字符串
    • pr格式化文本页,比如每页的行数等
  3. 文本排序的核心命令是sort

    • sort 命令中,可以指定列排序

文件的操作

  1. 文件权限-代表没有权限
  2. 文件的类型分为
    • 普通文件,通常位于存储设备上,分为文本和二进制,/usr/bin里面的是二进制文件
    • 目录
    • 伪文件,不占用磁盘空间,提供的是一种服务,比如proc,设备文件,命名管道等等
  3. find命令主要是-name(区分大小写),-iname(不区分大小写),需要模糊匹配需要搭配通配符
  4. 比较文件diff,它也可以比较目录
  5. 文件描述符是一个索引值,指向内核为每个进程所维护的打开文件的记录表
  6. LINUX内核规定每个进程最多打开文件数为1048576个
  7. 每个进程都与3个文件描述符关联
    • 标准输入 0
    • 标准输出 1
    • 标准错误 2
  8. 输出重定向基本语法
# [n]可以省略,n表述文件描述符,默认是1,注意,1和>没空格
cmd [n]> file

cmd 表示 Shell 命令,大于号>为重定向操作符,file 表示重定向的目标文件(可存在也可不存在,如果追加用>>)
9. 我们可以将标准错误和标准输出同时重定向

ls -lz &> filelist
  1. 使用输出重定向我们可以快速清空或创建一个文件
[root@linux chapter12]# :> errmsg
  1. 一组命令输出重定向
{ cmd1;cmd2;...; } [n]> file
  1. 输入重定向基本语法,默认文件描述符是0
cmd < file
  1. 输入输出结合使用
grep Bae > demo.txt < students.txt
  1. 我们可以通过输入重定向,来生成当前文档
[root@linux ~]# cat << eof 
> This is a test file. 
> There are two lines. 
> eof 
This is a test file. 
There are two lines.

这里的eof是代表结束,可以用其它的标志,但是不能还有空格和制表符
15. 重定向操作符只对当前命令有效,使用 exec 命令可以永久性地重定向,它可以让重定向对当前 Shell 进程中的所有命令有效

[mozhiyan@localhost ~]$ echo "重定向未发生"
重定向未发生
# 标准输出重定向到log.txt,那么以后的标准输出都到了log.txt
[mozhiyan@localhost ~]$ exec >log.txt
[mozhiyan@localhost ~]$ echo "c.biancheng.net"
[mozhiyan@localhost ~]$ echo "蔡彬的博客"
# 恢复标准输出到显示器,因为2也是到显示器,这样1也到显示器了,一切OK
[mozhiyan@localhost ~]$ exec 1>&2 
[mozhiyan@localhost ~]$ echo "重定向已恢复"
重定向已恢复
[mozhiyan@localhost ~]$ cat log.txt
c.biancheng.net
蔡彬的博客
  1. 所有对文件描述符的操作方式 exec 都支持

子Shell与进程处理

  1. 在脚本被执行的时候,当前的 Shell 会启动另外一个 Shell 实例,这样,每个SHELL脚本都运行在父SHELL的一个子进程中,可以使用下面的命令显示SHELL的层次
echo $SHLVL
  1. 当用户登录Linux或者UNIX后,操作系统会根据用户/etcpasswd文件中的配置启动一个SHELL进程,如果某个用户不需要登录,则可以将该用户的默认的 Shell 程序设置为/sbin/nologin
  2. 一旦SHELL脚本执行完毕,该SHELL子进程随即结束,并且返回到父SHELL中
    ,这个过程不影响父SHELL中的环境,比如我们再脚本中修改工作目录,退出后父SHELL的工作目录并没有改变
  3. 如果用户想要在当前的SHELL中执行脚本,可以使用下面的方式
[root@linux chapter13]# . ./ex13-1.sh 

这样在脚本里边就可以改变SHELL的路径了,使用圆点或者source命令使被调用脚本在当前SHELL进程中执行

  1. SHELL命令分为内部命令,保留字和外部命令
  • 内部命令 包含在SHELL工具包中的命令,例如cd
  • 保留字就比如break这种
  • 外部命令以磁盘文件的形式存在于磁盘中,用户登录时并不加载到内存,而是在需要的时候才被调进内存,绝大部分的SHELL命令都是外部命令,比如ls,外部命令一般位于/usr/bin及/usr/sbin等目录中,其中/usr/sbin中的命令通常与系统管理有关
  1. 用户在执行内部命令时不创建子SHELL,执行外部命令创建子SHELL,完成后返回父SHELL
  2. 在子SHELL中执行命令,可以在圆括号后面加上&放到后台执行
    • 圆括号结构
(command1;command2;command3;...)
  1. 子 Shell 中的代码可以访问父 Shell 中的变量的值。并且,当变量的值在子 Shell 中修改之后,在父 Shell 中可以获得变化之后的值
  2. 父SHELL无法获得子SHELL变量的值,但是我们可以通过临时文件或者命名管道的方式获取
  3. 一个作业可以有多个进程,比如下面有三个进程
[root@linux chapter13]# man ls | grep long | more 
  1. Ctrl+Z可以将前台作业挂起,然后用fg切换回来,可以用jobs命令查看后台列表,+号的作业是fg默认的,可以用disown命令或者kill删除
  2. 信号在 Linux 系统中是非常重要的一种通信机制。信号在软件层次上模拟了硬件中断机制。因此,简单地讲,信号即软件中断,比如KILL命令就是一种信号
  3. 用户可以对信号设定专门的处理函数,使用trap命令
trap [[arg] sigspec ...]

Shell 脚本调试技术

  1. if [ $x == “exit” ] 中括号两边一定要有空格
  2. 变量一定要用$引用
  3. 调试技术
  • echo,就像js中的alert
  • trap
    在 Shell 脚本执行的时候,会产生 3 个所谓的伪信号,分别为 EXIT、ERR 以及 DEBUG。其中,EXIT 信号在退出某个函数或者某个脚本执行完成时触发,ERR 信号在某条命令返 回非 0 状态时触发,DEBUG 信号在脚本的每一条命令执行之前触发,为这三个信号是由 Shell 产生的,而其他的信号是由操
    作系统产生的
trap 'command' signal

我们可以使用它来在命令出错,或者函数返回非0时,结合ERR定义一个函数来输出错误

  • tee 主要是用在管道调试,tee 命令会从标准输入读取数据,将其内容输出到标准输出设备,同时又可将内容保存成文件

  • 调试钩子
    就是一个全局变量,来控制调试开关

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值