Shell脚本学习总结篇

【Linux】Shell脚本学习总结篇

https://blog.csdn.net/bitboss/article/details/73019967

https://blog.csdn.net/bitboss/article/details/53037540

shell学习分为下面3个部分:

shell基本命令回顾
shell基本语法学习
awk/sed 工具学习
关于shell的介绍之类的在这里不做赘述!

shell基本命令回顾

1.1 最基础的常用命令

(注:命令选项直接 man 查看,不做说明)  
1
1.1.1 查看文件和目录的命令

ls : 列出目录下的清单;
cat: 连接显示文件内容
less/more: 分页显示文件内容,建议使用less,相比于more更方便;
head: 显示文件头部,可指定行数,默认显示10行;
tail: 显示文件尾部,可指定行数,默认显示10行;
file: 显示文件类型;
wc: 查看文件或统计信息;
find: 查找文件或目录(选项比较多,前面有博客专门介绍过)
1
2
3
4
5
6
7
8
部分演示:

1.1.2 操作文件和目录

touch:创建新文件(可以直接使用vim/vi/gredit等编辑器直接创建)
mkdir:创建目录,可以利用 -r选项递归创建
cp: 拷贝命令,拷贝目录时可以使用 -r 选项
ln: 创建链接命令,分为软连接和硬链接(有专门的文章介绍)
mv: 移动文件或者目录的命令,同时也是改名命令
rm: 删除命令,-r 删除目录, 谨慎使用;
1
2
3
4
5
6
1.1.3 管理文件或者目录的权限

ls -l : 可以列出文件和目录的权限信息;
chmod: 修改文件和目录的权限(需要了解字母及数字权限表示)
chown/chgrp: 改变属组和属主
setuid/setgid:设置用户或组权限位;
1
2
3
4
1.1.4 文本处理命令

sort : 文本排序
uniq : 文本去重
tr : 替换命令
grep : 查找字符串
diff: 文件对比,找出文件差异
1
2
3
4
5
部分演示: 


解释: history 命令列出用户的历史使用命令,然后通过awk 过滤出第二列,因为第一列是文件的行数标号, 接着进行一个sort排序,将所有相同的命令都放在一起方便接下来的uniq -c命令去重并且统计出每个命令出现的次数,再然后是 sort -nr -n选项的意思是按照数字的大小即uniq统计出的次数进行排序 -r 则是反向的意思,即本来是正序变为逆序;然后取其前十,即最常用的前十个命令,最后用一下 tr 命令将小写字母替换为大写字母;

对于命令的选项,我一贯的思想都是记住命令和常用的选项即可,太多的选项不需要强行去记忆,用的时候 man 一下或者 –help 看一下即可;

1.1.5 其它常用的命令

hostname : 查看主机名
w, who : 列出系统登录的用户
uptime : 查看系统运行时间
uname : 查看系统信息
date : 显示和设置系统日期和时间
id  : 显示用户属性
1
2
3
4
5
6
1.1.6 shell命令进阶

paster : 合并文本
dd : 备份和拷贝文件(和vim 和剪切命令一样)
tar : 打包和解包文件
mount, umount : 挂载和卸载存储介质
df : 报告文件系统磁盘空间利用率
du : 评估文件空间利用率
ps : 查看系统的进程
pidof : 列出进程的pid
top : 相当于 Linux 的任务管理器
& : 将作业后台运行
jobs : 查看作业
bg : 让挂起的进程在后台继续执行
fg : 将后台进程放入前台
fdisk: 查看系统的磁盘信息

部分演示: 


前后台切换演示: 


解释: 先执行 sleep 100 & 让这个进程在后台执行,然后我们先使用 ps 配合 grep 命令查看一下 sleep 进程的信息,接着 jobs 查看一下后台运行的作业, 使用 fg 命令使其继续在前台执行,我们可以看到显示了sleep 100 , 接着我们又不想让他继续执行了,使用 ctrl + z 使其挂起,我们用jobs查看,可以看出其处于 stopped 状态,接着使用 bg 命令使其继续在后台执行,查看状态, 处于running状态;

至此,shell的基本命令回顾完毕,这些都是脚本中常用的命令;

shell基本语法学习

这部分学习编写shell脚本的基本语法,估计篇幅比较长,因为要敲很多代码,所以,有瑕疵的地方请指出;

2.1 shell 语法篇

(这是回顾与复习的过程,所以不是小白教程,起码都吃过猪肉,看过猪跑)
1
2.1.1 shell 编程基础

1> 上面刚说过,得吃过猪肉,看过猪跑,那么最基本的shell脚本的编写格式应该知道;

#!/bin/bash
echo "hello world"
1
2
分析:还是 hello world 起步,第一行的 #!叫做 Shebang(我也不知道为什么这么叫), 然后后面的 /bin/bash 则是指定解释器,既然shell是门解释性语言,自然需要解释器,类似的,如果是 python脚本,则是 #! /bin/python 可能还需要一些编码格式的规定(utf - 8),如果没有指定解释器,默认选择 sh ; 同时还需要给文件可执行权限,否则会报错,虽然我们一般把shell 脚本文件命名为 .sh 的文件(在Linux中文件后缀只能起到标识的作用,没有实际意义);

2> shell 中的注释,在shell中注释的符号是 “#”;

3> shell 的变量

在shell中设置变量和平时在命令行设置变量是一样的,可以直接定义一个变量,例如: a=10  不需要声明类型,不需要分号;

如果需要明确指定变量的类型的话,可以只用declare的选项指定类型;

变量的作用域: 在shell 中,变量默认都具有全局属性,如果需要局部的变量则需要在变量的声明处加 local 关键字。如: local  a=10

变量的操作: 
    3.1 获取变量的值
    在命令行获取变量的值是通过 echo ${a}  打印变量的值到终端的,那么echo的作用是打印,'${}' 的作用不言而喻(花括号可省略,起分割的作用)。
    3.2 变量的运算
    let a+=1
    即使用 let 命令,当然除了 let 命令还有 '(())' 双括号,都可以进行变量的运算;
    3.3 参数变量
    说到shell的参数,有两个点,一个是命令行参数,一个是函数的参数,这里先说明命令行参数,函数的参数在后面学习函数的时候补充;

    首先,记住这几个特殊符号: $# $@ $* $1 $2 ...

    在运行程序的时候,经常需要带一些初始的参数,那么这些命令行参数到底是怎么传递进来的呢?
 

 


    $# : 除$0以外的参数的个数(文件名,命令除外,它们用$0查看);
    $@/*: 表示所有参数的集合
    $0,1,2...: 表示参数
1
2
3
注:取消变量的定义 unset

这里既然说到了变量,就顺带提一下环境变量和普通变量;

4> shell环境变量和普通变量

首先,明确两点,第一点即环境变量和普通变量在虚拟地址空间的存放位置,环境变量在栈顶的位置(高地址处),而普通变量是在数据段存放的;第二点,子进程会继承父进程的环境变量;

普通变量的命令行声明: a=10
将普通变量变为环境变量:export a

如何验证?
4.1  在父bash 中声明变量 a=10, 命令行敲 'bash' 命令相当于起了一个子bash, 在子 bash 中查找是否有 a变量;
1
2
3
4
5
6
7


(set 命令查看所有变量, env 命令查看所有环境变量,exit或者ctrl + d 退出子bash)

4.2  在父bash 中将变量 a 声明为环境变量 'export a', 在子bash 中查看变量 a;
1
2
3


2.1.2 shell 的条件执行

shell的条件执行其实和C差不多,具体的差异就在于语法格式的一些差别;
1
1> if 条件执行

不同于C的是,bash的条件测试不单单只是可以通过if进行判断,还要结合一些特殊的符号,命令和参数;
1
先列出基本的if语句的使用格式:

if true
then
    echo "hello world!"
else
    echo "see you world!"
fi 
1
2
3
4
5
6
:这就是 if 语句的基本使用格式,当然,中间还可以有 ’ elif ’ 相当于 C 的 else if ; 值得注意的是开始的 then 和 最后的 fi , 每个 if 都必须有一个fi 与之对应代表结束,因为没有了 ’ {} ‘;

前面说了,shell的条件判断需要结合一些命令,符号,选项来配合使用;

2.1 '[]' 和 test

'[]' 和 test 都被用作测试,如:
1
2
3
if [ -f install.log ]
then
    echo "hello"
fi

test -f install.log; echo "hello"
1
2
3
4
5
6
’ [ ] ’ 和 test 有很多选项,这里我就不一一演示,需要的话直接 man test; ( 注意: 使用 ‘[ ]’ 时, 需要两个空格,‘[’的后面, ‘]’的前面各一个);

不但这些,还有比较的符号;其中又分字符串和算数的不同;

(注: $? 查看上一条命令的返回值 )

追加一个知识点: 因为字符串的比较使用 ‘[]’ 时需要对 ><进行转义,所以shell提供 ’ [[ ]] ’ 符号,则不再需要转义,对于算术,shell提供 ’ (( )) ’ 则可以直接使用比较符进行比较(这在后面的例子中有体现);

算术: 


2.1.3 && 和 ||

&& : &&符号的前面的表达式为真才会执行 &&后面的表达式;
|| : || 符号前面的表达式为假才会执行 || 后面的表达式;
'!': 逻辑非

通常 && 和 || 配合使用,如:
1
2
3
4
5
‘’

2.1.4 shell 的 case 语句

shell的case语句的格式如下:
1
case $1 in 
1)
    echo "1"
    ;;
2)
    echo "2"
    ;;
esac

 

 


上面就是case语句的格式,这里刚好提醒一点,就是在shell中,不允许出现空语句,如果非要有空语句,则必须写上一个 冒号 ’ : ‘;

2.1.5 Bash 循环

shell的循环:for/while/until

下面只演示前两种,until不太用到;
1
2
3
for循环

for i in $(seq 10)
do
    echo -n $i
done

#类C 的for 循环:

for (( i=0; i<10; ++i ))
do
    echo -n $i
done 

 


注: seq 是生成连续序列的命令,而shell中执行命令的话,会用 ’ $() ‘; 
echo -n 选项则是取消换行,每个echo语句都会带一个换行,直接一个echo则代表换行;

while循环

值得一提的是break和continue关键字在shell中依然有效; 
1
i=1
while true
do
    if [ $i -gt 2 ];then
        echo $i
        break
    fi
    let i++
done
 

 


continue语句不做演示;

2.1.6 shell的函数

首先,shell函数的定义:
1
function  fun()
{
    if [ $# -ne 2 ];then
        return 1
    fi
    local a=$1
    local b=$2
    let c = a + b
    echo "hello $c"
    return 0
}

fun 1 2
if [ $? -ne 0 ];then
    echo "arguments fault!"
    exit
else
    echo "used right"
fi

 

 


上面就是一个简单的脚本,起作用是调用一个fun函数,判断调用是否正确;

分析: 从这个脚本中我们可以看出shell脚本函数的使用方式,从定义到参数的获取,再到返回值;最后还有函数的调用方式其实和命令的执行方式是一样的;

(注: function关键字可以省略但不建议,return 可以返回的值是 0-255)

额外知识点:在shell脚本中 双引号 和 单引号是有区别的,虽然在大部分场景中它们是一致的,但是如果含有特殊字符的话,双引号是没有对特殊字符进行转义的,所以上面的脚本中 “hello $c”可以顺利执行,但是单引号的话默认会对特殊字符转义的,例如: 


(注:shell函数对于参数的处理还有 shift 和 getopts 的处理方法,后期补充)

2.1.7 shell 重定向

说起重定向,估计不少同学都想到了管道;

但是,管道并不是重定向,重定向是将一个命令的输出结果作为下一个命令的输入,而重定向是将输出和文件相链接的;
1
2
3
重定向分为输入重定向和输出重定向,其中又有追加和覆盖的区别,总的来说就是下面四个符号:

’ > ‘, ’ >> ‘, ’ << ’ , ’ < ‘;

举例来说: 


当然,不仅可以这样,还可以将标准错误也重定向到文件;

ls l 2>test.sh
1
输入重定向:

例如: tr a-z  A-Z <         abcdef
        END
1
2
3


注: 这里的END不是固定的,只是起一个标签的作用,代表下次遇到END就结束输入;

重定向的这种用法还被用到项目中的configure文件,使configure文件可以自动生成Makefile文件,例如: 


2.1.8 shell 脚本从标准输入读取

这个其实只是一个read的使用,在shell中使用read从标准输入读取数据;
1
例如: 


结果: 


当然,read还有很多其他的使用方法,这里就不列了;

shell的基本语法复习到这,写的比较粗,中间还有一些遗漏,以后会更完善!

3.1 sed/awk 工具的简单使用

3.1.1  sed 工具

    sed 的背景我就不在这百科了,直接上手一些sed工具的基本使用规则,和一些简单的例子即可,不管是sed和awk工具在以后的工作中都肯定是常用的工具,但是,作为大学的学生,想熟练使用这两个工具估计得下挺大功夫,毕竟不常用;  所以我也只学习了一些简单的用法;

    sed 是一个文本处理工具,它为我们提供了很多的方便,刚开始知道sed这个工具的时候,其实挺害怕,觉得好复杂,估计用不了,而且在尝试了几次之后发现过几天就忘了,也就不了了之,这很正常,因为这些工具的使用就是唯手熟尔;现在只要了解它就够了;

学习sed和awk工具还有一个前提就是正则表达式的学习,这也是很多同学望而却步的原因,这里我就不对正则表达式进行百科了,不会就查,用的时间长了就记住了;

 

 


()sed的工作方式

sed是一行一行处理文本的,还有需要知道sed有一个HOLD空间和模式空间,HOLD用来作为文档处理的暂存空间,不能有任何的操作,所有的操作只能在模式空间进行;

sed常用的选项:
    -e: 它告诉sed将下一个参数解释为sed指令,即需要连续多个处理时使用;
    -f : 指定由sed指令组成的脚本的名称;
    -i : 直接在读取的内容进行修改,如果没有—i,不会源文件造成任何修改;
    -n: 静默模式,即只输出匹配的行,如果没有-n则匹配行会和源文件全部输出;


现在先不做演示,等把下面的编辑命令也复习完毕,一块做演示;

sed的编辑命令有24个之多,在这里只学习常用的几个:
追加(a),更改(c),删除(d),插入(i),替换(s),打印(l),打印行号(=),转换(y);

 


部分演示: 


这些小的编辑命令多练习一下就熟悉了,接下来练习一个模式空间和HOLD空间的切换的例子,结束sed的复习;

下面这些选项则是需要用到暂存空间时要用到的选项:

+ g:[address[,address]]g 将hold space中的内容拷⻉贝到pattern space中,原来pattern space⾥里的内容清除
 + G:[address[,address]]G 将hold space中的内容append到pattern space\n后
+ h:[address[,address]]h 将pattern space中的内容拷⻉贝到hold space中,原来的hold space⾥里的内容被清除
+ H:[address[,address]]H 将pattern space中的内容append  hold space\n后
+ d:[address[,address]]d 删除pattern中的所有⾏行,并读⼊入下⼀一新⾏行到pattern中
+ D:[address[,address]]D 删除multiline pattern中的第⼀一⾏行,不读⼊入下⼀一⾏行
+ N,添加下一行至pattern space内;
+ x:交换保持空间和模式空间的内容

 


求1~100的和

两种方式:
1


分析:第一个例子利用了暂存空间和模式空间的特点进行求和,其中 $ 代表最后一行; ‘^’ 代表第一行; 然后利用选项H 和 x; 其中利用sed的s编辑命令和正则表达式把换行换为加号,最后通过管道把表达式交给bc计算器,得到最终结果;

第二个例子则是利用sed的标签,没有用到暂存空间; 其中 :a是设置了一个 a标签, ba的作用是跳转到a标签;

感觉这种工具只有自己去实践了才能领会,反正我是写的晕晕的;

awk工具的简单使用

awk可是厉害了,awk严格说也是一门语言,语法很多,也很强大,在这里我只学了个皮毛,也就只负责皮毛的这块了;

既然有了sed为什么还要有awk呢?   肯定是因为awk比sed更加强大,就最明显的一点,sed只能一行一行处理数据,不能处理一列一列的数据,而awk就可以做到,而且awk还可以利用类C的语法结构,简直强大,可是我用的还是不熟;

关于awk的使用,在前面复习shell语法的时候其实都用到了,就是找出你在Linux上最常用的十个命令:
history | awk '{print $1}' | sort | uniq -c | sort -nr |head

awk 的默认的列分割符是空格,我们也可以指定分割符,利用 -F选项;
例如:
 


awk 还有一个特点就是它的 BEGIN 块和 END 块;

BEGIN块的作用是在awk执行匹配之前先执行的语句,END自然就是awk处理完之后执行的语句;

例如: 


awk和sed简单的使用就写到这了,感觉烂尾了,写的好累写不下去了,也是这俩个工具要掌握的话需要很多篇幅的,总之就这样了,下一篇,mysql数据库的学习
 

你可能感兴趣的:(Shell脚本学习总结篇)