Linux shell从入门到精通 - 我的星期八

时间:2024-01-30 18:43:35

Linux shell从入门到精通

 
前言

 

关于本文档

文档名称    Shell 从入门到精通
腾讯课堂    http://opsdev.ke.qq.com

博客    http://blog.51cto.com/lizhenliang

GitHub    https://github.com/lizhenliang/Shell-Python-Document
QQ 技术群    249171211(Python 运维开发群)

516039855(Docker 技术交流群)

说明    本文档均为个人经验总结,转发请保留出处,抵制不道德行为。

文档会不定期修改或新增知识点,请关注群状态。
最后更新时间    2017-11-24


学习目标
熟悉 Linux 系统常用命令与工具,掌握 Shell 脚本语言语法结构,能独立编写 Shell 脚本,完成自动 化运维常规任务,提高工作效率,为以后学习其他语言打下坚实的基础。
目标人群
运维工程师、开发工程师、Linux 系统爱好者或已经具备其他编程语言的人群。 操作系统
本文档实验均采用 CentOS7_X64 系统。需要注意的是,与 CentOS6 或者 Ubuntu 相比,个别命令使用 方法会有点不同。
 
目录
第一章    Shell 基础知识     8
1.1 Shell 简介    8
1.2 Shell 基本分两大类    9
1.3 第一个 Shell 脚本    9
1.4 Shell 变量    9
1.5 变量引用    12
1.6 双引号和单引号    13
1.7 注释    14
第二章    Shell 字符串处理之${}     14
2.1 获取字符串长度    14
2.2 字符串切片    14
2.3 替换字符串    15
2.4 字符串截取    15
2.5 变量状态赋值    16
2.6 字符串颜色    16
第三章    Shell 表达式与运算符     17
3.1 条件表达式    17
3.2 整数比较符    18
3.3 字符串比较符    18
3.4 文件测试    19
3.5 布尔运算符    19
3.6 逻辑判断符    20
3.7 整数运算    20
3.8 其他运算工具(let/expr/bc)    21
3.9 Shell 括号用途总结    22
第四章    Shell 流程控制     23
4.1 if 语句    23
4.2 for 语句    25
4.3    while 语句    26
4.4    breakcontinue 语句    28
4.5 case 语句    29
4.6 select 语句    30
第五章    Shell 函数与数组     32
5.1 函数    32
 
5.2 数组    34
第六章    Shell 正则表达式     35
第七章    Shell 文本处理三剑客     38
7.1    grep    38
7.2    sed    42
7.2.1 匹配打印(p)    44
7.2.2 匹配删除(d)    46
7.2.3 替换(s///)    47
7.2.4 多重编辑(-e)    50
7.2.5 添加新内容(a、i 和 c)    50
7.2.6 读取文件并追加到匹配行后(r)    52
7.2.7 将匹配行写到文件(w)    52
7.2.8 读取下一行(n 和 N)    53
7.2.9 打印和删除模式空间第一行(P 和 D)    55
7.2.10 保持空间操作(h 与 H、g 与 G 和 x)    55
7.2.11 标签(:、b 和 t)    57
7.2.12 忽略大小写匹配(I)    59
7.2.13 获取总行数(#)    59
8.3 awk    59
8.3.1 选项    60
8.3.2 模式    60
8.3.3 内置变量    65
8.3.4 操作符    70
8.3.5 流程控制    74
8.3.6 数组    77
8.3.7 内置函数    80
8.3.8 I/O 语句    84
8.3.9 printf 语句    87
8.3.10 自定义函数    88
8.3.11 需求案例    89
第八章    Shell 标准输入、输出和错误     94
8.1 标准输入、输出和错误    94
8.2 重定向符号    94
8.3 重定向输出    95
8.4 重定向输入    95
 
8.5 重定向标准输出和标准错误    95
8.6 重定向到空设备    96
8.7 read 命令    97
第九章    Shell 信号发送与捕捉     98
9.1 Linux 信号类型    98
9.2 kill 命令    100
9.3 trap 命令    100
第十章    Shell 编程时常用的系统文件     102
10.1 Linux 系统目录结构    102
10.2 环境变量文件    103
10.3 系统配置文件    103
10.4 /dev 目录    104
10.5 /proc 目录    104
10.5.1 /proc    105
10.5.2    /proc/net    105
10.5.3    /proc/sys    106
第十一章    Shell 常用命令与工具     108
11.1 ls    108
11.2    echo    109
11.3    printf    109
11.4 cat    110
11.5 tac    111
11.6 rev    111
11.7 wc    111
11.8 cp    111
11.9 mkdir    112
11.10 mv    112
11.11    rename    112
11.12    dirname    113
11.13    basename    113
11.14 du    113
11.15 cut    114
11.16 tr    114
11.17 stat    115
11.18 seq    115
 
11.19    shuf    116
11.20    sort    116
11.21    uniq    117
11.22 tee    118
11.23    join    119
11.24    paste    119
11.25    head    120
11.26    tail    120
11.27    find    120
11.28    xargs    122
11.29 nl    122
11.30    date    123
11.31    wget    124
11.32    curl    126
11.33 scp    127
11.34    rsync    128
11.35    nohup    128
11.36    iconv    129
11.37    uname    129
11.38    sshpass    129
11.39 tar    130
11.40    logger    130
11.41    netstat    131
11.42 ss    131
11.43 lsof    132
11.44 ps    133
11.45 top    134
11.46 free    135
11.47 df    136
11.48    vmstat    136
11.49    iostat    137
11.50 sar    137
11.51 dstat    138
11.52 ip    138
11.53 nc    139
 
11.54    time    140
11.55    eval    141
11.56 ssh    141
11.57 iptables    142
第十二章    Shell 脚本编写实战     145
12.1 获取随机字符串或数字    145
12.2 定义一个颜色输出字符串函数    146
12.3 批量创建用户    147
12.4 检查软件包是否安装    147
12.5 检查服务状态    147
12.6 检查主机存活状态    148
12.7 监控 CPU、内存和硬盘利用率    149
12.8 批量主机磁盘利用率监控    150
12.9 检查网站可用性    151
12.10 检查 MySQL 主从同步状态    152
12.11 屏蔽访问频繁的 IP    153
12.12 判断输入是否为 IP    154
12.13 判断输入是否为数字    155
12.14 找出包含关键字的文件    155
12.15 监控目录,将新创建的文件名追加到日志中    156
12.16 多个网卡选择    156
12.17 查看网卡实时流量    157
12.18 MySQL 数据库备份    158
12.19 Nginx 启动脚本    158
12.20 选择 SSH 连接主机    160
12.21 FTP 下载文件    160
12.22 输入五个 100 数之内的字符,统计和、最小和最大    161
12.23 将结果分别赋值给变量    161
12.24 批量修改文件    162
12.25 统计当前目录中以.html 结尾的文件总大小    162
12.26 扫描主机端口状态    162
12.27 Expect 实现 SSH 免交互执行命令    163
12.28 批量修改服务器用户密码    165
12.29 打印乘法口诀    165
12.30 getopts 工具完善脚本命令行参数    166
 
第一章    Shell 基础知识

1.1  Shell 简介

Shell 是一个 C 语言编写的脚本语言,它是用户与 Linux 的桥梁,用户输入命令交给 Shell 处理, Shell 将相应的操作传递给内核(Kernel),内核把处理的结果输出给用户。 下面是流程示意图:
 
Shell 既然是工作在 Linux 内核之上,那我们也有必要了解下 Linux 相关知识。
Linux 是一套免费试用和*传播的类 Unix 操作系统,是一个基于 POSIX 和 UNIX 的多用户、多任 务、支持多线程和多 CPU 的操作系统。
1983 年 9 月 27 日,Richard Stallman(理查德-马修-斯托曼)发起 GNU 计划,它的目标是创建一 套完全*的操作系统。为保证 GNU 软件可以*的使用、复制、修改和发布,所有的 GNU 软件都 有一份在禁止其他人添加任何限制的情况下授权所有权利给任何人的协议条款,GNU 通用公共许可 证(GNU General Plubic License,GPL),说白了就是不能做商业用途。
GNU 是"GNU is Not Unix"的递归缩写。UNIX 是一种广泛使用的商业操作系统的名称。
1985 年,Richard Stallman 又创立了*软件基金会(Free Software Foundation,FSF)来为 GNU 计划提供技术、法律以及财政支持。
1990 年,GNU 计划开发主要项目有 Emacs(文本编辑器)、GCC(GNU Compiler Collection,GNU 编 译器集合)、Bash 等,GCC 是一套 GNU 开发的编程语言编译器。还有开发一些 UNIX 系统的程序库和 工具。
1991 年,Linuxs Torvalds(林纳斯- 托瓦兹)开发出了与 UNIX 兼容的 Linux 操作系统内核并在 GPL 条款下发布。
1992 年,Linux 与其他 GUN 软件结合,完全*的 GUN/Linux 操作系统正式诞生,简称 Linux。 1995 年 1 月,Bob Young 创办 ACC 公司,以 GNU/Linux 为核心,开发出了 RedHat Linux 商业版。 Linux 基本思想有两点:第一,一切都是文件;第二,每个软件都有确定的用途。与 Unix 思想十分
相近。
 
1.2  Shell 基本分两大类

1.2.1    图形界面 Shell(GUI Shell)
GUI 为 Unix 或者类 Unix 操作系统构造一个功能完善、操作简单以及界面友好的桌面环境。主流桌 面环境有 KDE,Gnome 等。
1.2.2    命令行界面 Shell(CLI Shell)
CLI  是在用户提示符下键入可执行指令的界面,用户通过键盘输入指令,完成一系列操作。 在 Linux 系统上主流的 CLI 实现是 Bash,是许多 Linux 发行版默认的 Shell。还有许多 Unix 上 Shell,例如 tcsh、csh、ash、bsh、ksh 等。

1.3    第一个 Shell 脚本

本教程主要讲解在大多 Linux 发行版下默认 Bash Shell。Linux 系统是 RedHat 下的 CentOS 操作系 统,完全免费。与其商业版 RHEL(Red Hat Enterprise Linux)出自同样的源代码,不同的是 CentOS 并不包含封闭源代码软件和售后支持。
用 vi 打开 test.sh,编写:
 
第一行指定解释器,第二行打印 Hello world!
写好后,开始执行,执行 Shell 脚本有三种方法: 方法 1:直接用 bash 解释器执行
 
当前终端会新生成一个子 bash 去执行脚本。
方法 2:添加可执行权限
 
这种方式默认根据脚本第一行指定的解释器处理,如果没写以当前默认 Shell 解释器执行。
方法 3:source 命令执行,以当前默认 Shell 解释器执行
 

1.4    Shell 变量

1.4.1 系统变量
 
在命令行提示符直接执行 env、set 查看系统或环境变量。env 显示用户环境变量,set 显示 Shell 预先定义好的变量以及用户变量。可以通过 export 导出成用户变量。
一些写 Shell 脚本时常用的系统变量:
$SHELL    默认 Shell
$HOME    当前用户家目录
$IFS    内部字段分隔符
$LANG    默认语言
$PATH    默认可执行程序路径
$PWD    当前目录
$UID    当前用户 ID
$USER    当前用户
$HISTSIZE    历史命令大小,可通过 HISTTIMEFORMAT 变量设置命令执行时间
$RANDOM    随机生成一个 0 至 32767 的整数
$HOSTNAME    主机名
1.4.2 普通变量与临时环境变量
普通变量定义:VAR=value 临时环境变量定义:export VAR=value 变量引用:$VAR 下面看下他们之间区别:
Shell 进程的环境变量作用域是 Shell 进程,当 export 导入到系统变量时,则作用域是 Shell 进程 及其 Shell 子进程。
 
 

 
ps axjf 输出的第一列是 PPID(父进程 ID),第二列是 PID(子进程 ID)
当 SSH 连接 Shell 时,当前终端 PPID(-bash)是 sshd 守护程序的 PID(root@pts/0),因此在当 前终端下的所有进程的 PPID 都是-bash 的 PID,比如执行命令、运行脚本。
所以当在-bash 下设置的变量,只在-bash 进程下有效,而-bash 下的子进程 bash 是无效的,当 export 后才有效。
进一步说明:再重新连接 SSH,去除上面定义的变量测试下

 
所以在当前 shell 定义的变量一定要 export,否则在写脚本时,会引用不到。
 
还需要注意的是退出终端后,所有用户定义的变量都会清除。
在/etc/profile 下定义的变量就是这个原理,后面有章节会讲解 Linux 常用变量文件。 1.4.3 位置变量
位置变量指的是函数或脚本后跟的第 n 个参数。
$1-$n,需要注意的是从第 10 个开始要用花括号调用,例如${10} shift 可对位置变量控制,例如:
 
每执行一次 shift 命令,位置变量个数就会减一,而变量值则提前一位。shift n,可设置向前移动
n 位。
1.4.4 特殊变量
$0    脚本自身名字
$?    返回上一条命令是否执行成功,0 为执行成功,非 0 则为执行失败
$#    位置参数总数
$*    所有的位置参数被看做一个字符串
$@    每个位置参数被看做独立的字符串
$$    当前进程 PID
$!    上一条运行后台进程的 PID

1.5 变量引用

赋值运算符    示例
=    变量赋值
+=    两个变量相加
1.5.1 自定义变量与引用
 
 
 
Shell 中所有变量引用使用$符,后跟变量名。
有时个别特殊字符会影响正常引用,那么需要使用${VAR},例如:
 
还有时候变量名与其他字符串紧碍着,也会误认为是整个变量:
 
1.5.2 将命令结果作为变量值
 
这里的反撇号等效于$(),都是用于执行 Shell 命令。

1.6 双引号和单引号

在变量赋值时,如果值有空格,Shell 会把空格后面的字符串解释为命令:
 
看不出什么区别,再举个说明:
 
 
 
单引号是告诉 Shell 忽略特殊字符,而双引号则解释特殊符号原有的意义,比如$、!。

1.7 注释

Shell 注释也很简单,只要在每行前面加个#号,即表示 Shell 忽略解释。 第二章    Shell 字符串处理之${}
上一章节讲解了为什么用${}引用变量,${}还有一个重要的功能,就是文本处理,单行文本基本上 可以满足你所有需求。

2.1 获取字符串长度

 

2.2 字符串切片

格式:
${parameter:offset}
${parameter:offset:length}
截取从 offset 个字符开始,向后 length 个字符。
 
 
 

2.3 替换字符串

格式:${parameter/pattern/string}
 
patterm 前面开头一个正斜杠为只匹配第一个字符串,两个正斜杠为匹配所有字符。
2.4 字符串截取 格式:
${parameter#word}    # 删除匹配前缀
${parameter##word}
${parameter%word}    # 删除匹配后缀
${parameter%%word}
# 去掉左边,最短匹配模式,##最长匹配模式。
% 去掉右边,最短匹配模式,%%最长匹配模式。
 
 
 

2.5 变量状态赋值

${VAR:-string}    如果 VAR 变量为空则返回 string
${VAR:+string}    如果 VAR 变量不为空则返回 string
${VAR:=string}    如果 VAR 变量为空则重新赋值 VAR 变量值为 string
${VAR:?string}    如果 VAR 变量为空则将 string 输出到 stderr
 
${}主要用途大概就这么多了,另外还可以获取数组元素,在后面章节会讲到。

2.6 字符串颜色 再介绍下字符串输出颜色,有时候关键地方需要醒目,颜色是最好的方式:
 
\033[1;31;40m    # 1 是显示方式,可选。31 是字体颜色。40m 是字体背景颜色。
\033[0m    # 恢复终端默认颜色,即取消颜色设置。 示例:
 
 


第三章    Shell 表达式与运算符

3.1 条件表达式

表达式    示例
[ expression ]    [ 1 -eq 1 ]
[[ expression ]]    [[ 1 -eq 1 ]]
 
test    expression    test 1 -eq 1 ,等同于[]

3.2 整数比较符

比较符    描述    示例
-eq,equal    等于    [ 1 -eq 1 ]为 true
-ne,not equal    不等于    [ 1 -ne 1 ]为 false
-gt,greater than    大于    [ 2 -gt 1 ]为 true
-lt,lesser than    小于    [ 2 -lt 1 ]为 false
-ge,greater or equal    大于或等于    [ 2 -ge    1 ]为 true
-le,lesser or equal    小于或等于    [ 2 -le 1 ]为 false

3.3 字符串比较符

运算符    描述    示例
==    等于    [ "a" == "a"    ]为 true
!=    不等于    [ "a" != "a"    ]为 false

>    
大于,判断字符串时根据 ASCII 码表顺序,不常用    在[]表达式中:[ 2 \> 1 ]为 true
在[[]]表达式中:[[ 2 > 1 ]]为 true
在(())表达式中:(( 3 > 2 ))为 true

<    
小于,判断字符串时根据 ASCII 码表顺序,不常用    在[]表达式中:[ 2 \< 1 ]为 false
在[[]]表达式中:[[ 2 < 1 ]]为 false
在(())表达式中:(( 3 < 2 ))为 false
>=    大于等于    在(())表达式中:(( 3 >= 2 ))为 true
<=    小于等于    在(())表达式中:(( 3 <= 2 ))为 false

-n    
字符串长度不等于 0 为真    VAR1=1;VAR2=""
[ -n "$VAR1" ]为 true [ -n "$VAR2" ]为 false

-z    
字符串长度等于 0 为真    VAR1=1;VAR2=""
[ -z "$VAR1" ]为 false [ -z "$VAR2" ]为 true
 

str    
字符串存在为真    VAR1=1;VAR2=""
[ $VAR1 ]为 true [ $VAR2 ]为 false
需要注意的是,使用-z 或-n 判断字符串长度时,变量要加双引号。
举例说明:
 
 

3.4 文件测试

测试符    描述    示例
-e    文件或目录存在为真    [ -e path ] path 存在为 true
-f    文件存在为真    [ -f file_path ] 文件存在为 true
-d    目录存在为真    [ -d dir_path ] 目录存在为 true
-r    有读权限为真    [ -r    file_path ]    file_path 有读权限为 true
-w    有写权限为真    [ -w    file_path ]    file_path 有写权限为 true
-x    有执行权限为真    [ -x    file_path ]    file_path 有执行权限为 true

-s    文件存在并且大小大于 0 为真    [ -s    file_path ]    file_path 存在并且大小大于 0 为 true

3.5 布尔运算符

运算符    描述    示例
 
!    非关系,条件结果取反    [ ! 1 -eq 2 ]为 true
-a    和关系,在[]表达式中使用    [ 1 -eq 1 -a 2 -eq 2 ]为 true
-o    或关系,在[]表达式中使用    [ 1 -eq 1 -o 2 -eq 1 ]为 true

3.6 逻辑判断符

判断符    描述    示例

&&    
逻辑和,在[[]]和(())表达式中 或判断表达式是否为真时使用    [[ 1 -eq 1 && 2 -eq 2 ]]为 true
(( 1 == 1 && 2 == 2 ))为 true
[ 1 -eq 1 ] && echo yes 如果&&前 面表达式为 true 则执行后面的

||    
逻辑或,在[[]]和(())表达式中 或判断表达式是否为真时使用    [[ 1 -eq 1 || 2 -eq 1 ]]为 true
(( 1 == 1 || 2 == 2 ))为 true
[ 1 -eq 2 ] || echo yes 如果||前 面表达式为 false 则执行后面的

3.7 整数运算

运算符    描述
+    加法
-    减法
*    乘法
/    除法
%    取余

运算表达式    示例
$(())    $((1+1))
$[]    $[1+1]
上面两个都不支持浮点运算。
$(())表达式还有一个用途,三目运算:
 
 
 

3.8 其他运算工具(let/expr/bc)

除了 Shell 本身的算数运算表达式,还有几个命令支持复杂的算数运算:
命令    描述    示例



let    


赋值并运算,支持++、--    let VAR=(1+2)*3 ; echo $VAR x=10 ; y=5
let x++;echo $x 每执行一次 x 加 1 let y--;echo $y 每执行一次 y 减 1 let x+=2 每执行一次 x 加 2
let x-=2 每执行一次 x 减 2

expr    
乘法*需要加反斜杠转义\*    expr 1 \* 2    运算符两边必须有空格
expr \( 1 + 2 \) \* 2    使用双括号时要转义


bc    

计算器,支持浮点运算、 平方等    bc 本身就是一个计算器,可直接输入命令,进入解释器。 echo 1 + 2 |bc 将管道符前面标准输出作为 bc 的标准输入 echo "1.2+2" |bc
echo "10^10" |bc
echo \'scale=2;10/3\' |bc    用 scale 保留两位小数点
由于 Shell 不支持浮点数比较,可以借助 bc 来完成需求:
 
expr 还可以对字符串操作:
 
 
 

3.9  Shell 括号用途总结

看到这里,想一想里面所讲的小括号、中括号的用途,是不是有点懵逼了。那我们总结一下!

( )    用途 1:在运算中,先计算小括号里面的内容 用途 2:数组
用途 3:匹配分组

(( ))    用途 1:表达式,不支持-eq 这类的运算符。不支持-a 和-o,支持<=、>=、<、>这类 比较符和&&、||
用途 2:C 语言风格的 for(())表达式
$( )    执行 Shell 命令,与反撇号等效

$(( ))    用途 1:简单算数运算
用途 2:支持三目运算符    $(( 表达式?数字:数字    ))
[ ]    条件表达式,里面不支持逻辑判断符

[[ ]]    条件表达式,里面不支持-a 和-o,不支持<=和>=比较符,支持-eq、<、>这类比较 符。支持=~模式匹配,也可以不用双引号也不会影响原意,比[]更加通用
$[ ]    简单算数运算

{ }    对逗号(,)和点点(...)起作用,比如 touch {1,2}创建 1 和 2 文件,touch
{1..3}创建 1、2 和 3 文件

${ }    用途 1:引用变量 用途 2:字符串处理
 
第四章    Shell 流程控制

流程控制是改变程序运行顺序的指令。

4.1    if 语句

格式:if list; then list; [ elif list; then list; ] ... [ else list; ] fi
4.1.1 单分支
 
示例:
 
4.1.2 双分支
 
示例 1:
 
示例 2:判断 crond 进程是否运行
 
 
 
示例 3:检查主机是否存活
 
if 语句可以直接对命令状态进行判断,就省去了获取$?这一步!
4.1.3 多分支
 
当不确定条件符合哪一个时,就可以把已知条件判断写出来,做相应的处理。
示例 1:
 
如果第一个条件符合就不再向下匹配。
示例 2:根据 Linux 不同发行版使用不同的命令安装软件
 
 
4.2    for 语句

格式:for name [ [ in [ word ... ] ] ; ] do list ; done
 
示例:
 
for 的语法也可以这么写:
 
默认 for 循环的取值列表是以空白符分隔,也就是第一章讲系统变量里的$IFS:
 
如果想指定分隔符,可以重新赋值$IFS 变量:
 
 
 
for 循环还有一种 C 语言风格的语法,常用于计数、打印数字序列:
for (( expr1 ; expr2 ; expr3 )) ; do list ; done
 
示例 1:检查多个主机是否存活
 
示例 2:检查多个域名是否可以访问
 

4.3    while 语句

格式:while list; do list; done
 
示例 1:
 
 
 
当条件表达式为 false 时,终止循环。
示例 2:条件表达式为 true,将会产生死循环
 
也可以条件表达式直接用 true:
 
还可以条件表达式用冒号,冒号在 Shell 中的意思是不做任何操作。但状态是 0,因此为 true:
 
示例 3:逐行处理文本
文本内容:
 
要想使用 while 循环逐行读取 a.txt 文件,有三种方式:
方式 1:
 
方式 2:
 
 
 
方式 3:
 
与 while 关联的还有一个 until 语句,它与 while 不同之处在于,是当条件表达式为 false 时才循
环,实际使用中比较少,这里不再讲解。

4.4    breakcontinue 语句

break 是终止循环。 continue 是跳出当前循环。
示例 1:在死循环中,满足条件终止循环
 
里面用了 if 判断,并用了 break 语句,它是跳出循环。与其关联的还有一个 continue 语句,它是
跳出本次循环。
示例 2:举例子说明 continue 用法
 
 
 
当变量 N 等于 3 时,continue 跳过了当前循环,没有执行下面的 echo。 注意:continuebreak 语句只能循环语句中使用。

4.5    case 语句

case 语句一般用于选择性来执行对应部分块命令。
格式:case word in [ [(] pattern [ | pattern ] ... ) list ;; ] ... esac
 
每个模式必须以右括号结束,命令结尾以双分号结束。
示例:根据位置参数匹配不同的模式
 
上面例子是不是有点眼熟,在 Linux 下有一部分服务启动脚本都是这么写的。
模式也支持正则,匹配哪个模式就执行那个:
 
 
模式支持的正则有:*、?、[ ]、[.-.]、|。后面有章节单独讲解 Shell 正则表达式。

4.6    select 语句

select 是一个类似于 for 循环的语句。 格式:select name [ in word ] ; do list ; done
 
示例:
 
 
用户输入编号会直接赋值给变量 mysql_version。作为菜单用的话,循环第二次后就不再显示菜单 了,并不能满足需求。
在外面加个死循环,每次执行一次 select 就 break 一次,这样就能每次显示菜单了:
 
如果再判断对用户输入的编号执行相应的命令,如果用 if 语句多分支的话要复杂许多,用 case 语
句就简单多了。
 
 
 
如果不想用默认的提示符,可以通过重新赋值变量 PS3 来自定义。这下就比较完美了!
第五章    Shell 函数与数组 5.1 函数
格式:
 
function 关键字可写,也可不写。
示例 1:
 
Shell 函数很简单,函数名后跟双括号,再跟双大括号。通过函数名直接调用,不加小括号。
示例 2:函数返回值
 
 
 
return 在函数中定义状态返回值,返回并终止函数,但返回的只能是 0-255 的数字,类似于 exit。
示例 3:函数传参
 
通过 Shell 位置参数给函数传参。
函数也支持递归调用,也就是自己调用自己。 例如:
 
执行会一直在调用本身打印 hello,这就形成了闭环。
像经典的 fork 炸弹就是函数递归调用:
:(){ :|:& };: 或    .(){.|.&};.
这样看起来不好理解,我们更改下格式:
 
再易读一点:
 
分析下:
:(){    } 定义一个函数,函数名是冒号。
: 调用自身函数
| 管道符
: 再一次递归调用自身函数
:|: 表示每次调用函数":"的时候就会生成两份拷贝。 & 放到后台
; 分号是继续执行下一个命令,可以理解为换行。
: 最后一个冒号是调用函数。 因此不断生成新进程,直到系统资源崩溃。
 
一般递归函数用的也少,了解下即可! 5.2  数组
数组是相同类型的元素按一定顺序排列的集合。 格式:
array=(元素 1 元素 2 元素 3 ...) 用小括号初始化数组,元素之间用空格分隔。 定义方法 1:初始化数组
array=(a b c)
定义方法 2:新建数组并添加元素 array[下标]=元素
定义方法 3:将命令输出作为数组元素 array=($(command))
数组操作:

 
 
数组下标从 0 开始。
示例 1:讲 seq 生成的数字序列循环放到数组里面
 
示例 2:遍历数组元素
 


第六章    Shell 正则表达式

正则表达式在每种语言中都会有,功能就是匹配符合你预期要求的字符串。 Shell 正则表达式分为两种:
基础正则表达式:BRE(basic  regular  express) 扩展正则表达式:ERE(extend regular express),扩展的表达式有+、?、|和() 下面是一些常用的正则表达式符号,我们先拿 grep 工具举例说明。
符号    描述    示例

.    匹配除换行符(\n)之外的任 意单个字符    匹配 123:
echo -e "123\n456" |grep \'1.3\'

^    
匹配前面字符串开头    匹配以 abc 开头的行:
echo -e "abc\nxyz" |grep ^abc
$    匹配前面字符串结尾    匹配以 xyz 结尾的行:
 
        echo -e "abc\nxyz" |grep xyz$

*    
匹配前一个字符零个或多个    匹配 x、xo 和 xoo:
echo -e "x\nxo\nxoo\no\noo" |grep "xo*" x 是必须的,批量了 0 零个或多个


+    

匹配前面字符 1 个或多个    匹配 abc 和 abcc:
echo -e "abc\nabcc\nadd" |grep -E \'ab+\' 匹配单个数字:echo "113" |grep -o \'[0-9]\'
连续匹配多个数字:echo "113" |grep -E -o \'[0-
9]+\'

?    
匹配前面字符 0 个或 1 个    匹配 ac 或 abc:
echo -e "ac\nabc\nadd" |grep -E \'a?c\'

[ ]    匹配中括号之中的任意一个 字符    匹配 a 或 c:
echo -e "a\nb\nc" |grep \'[ac]\'

[ .-.]    匹配中括号中范围内的任意 一个字符    匹配所有字母:
echo -e "a\nb\nc" |grep \'[a-z]\'


[^]    
匹配[^字符]之外的任意一 个字符    匹配 a 或 b:
echo -e "a\nb\nc" |grep \'[^c-z]\' 匹配末尾数字:echo "abc:cde;123" |grep -E \'[^;]+$\'

^[^]    匹配不是中括号内任意一个 字符开头的行    匹配不是#开头的行:
grep \'^[^#]\' /etc/httpd/conf/httpd.conf
{n}或
{n,}    匹配花括号前面字符至少 n 个字符    匹配 abc 字符串(至少三个字符以上字符串): echo -e "a\nabc\nc" |grep -E \'[a-z]{3}\'

{n,m}    
匹配花括号前面字符至少 n 个字符,最多 m 个字符    匹配 12 和 123(不加边界符会匹配单个字符): echo -e "1\n12\n123\n1234" |grep -E -w -o \'[0- 9]{2,3}\'

\<    
边界符,匹配字符串开始    匹配开始是 123 和 1234:
echo -e "1\n12\n123\n1234" |grep \'\<123\'

\>    
边界符,匹配字符串结束    匹配结束是 1234:
echo -e "1\n12\n123\n1234" |grep \'4\>\'



( )    
单元或组合:将小括号里面 作为一个组合 分组:匹配小括号中正则表 达式或字符。\n 反向引 用,n 是数字,从 1 开始编    单元:匹配 123a 字符串
echo "123abc" |grep -E -o \'([0-9a-z]){4}\' 分组:匹配 11
echo "113abc" |grep -E -o \'(1)\1\' 匹配出现 xo 出现零次或多次:
echo -e "x\nxo\nxoo\no\noo" |egrep "(xo)*"
 
    号,表示引用第 n 个分组匹 配的内容    

|    
匹配竖杠两边的任意一个    匹配 12 和 123:
echo -e "1\n12\n123\n1234" |grep -E \'12\>|123\>\'

\    转义符,将特殊符号转成原 有意义    
1.2,匹配 1.2:1\.2,否则 112 也会匹配到

Posix 字符    描述
[:alnum:]    等效[a-zA-Z0-9]
[:alpha:]    等效[a-zA-Z]
[:lower:]    等效[a-z]
[:upper:]    等效[A-Z]
[:digit:]    等效[0-9]
[:space:]    匹配任意空白字符,等效[\t\n\r\f\v]
[:graph:]    非空白字符
[:blank:]    空格与定位字符
[:cntrl:]    控制字符
[:print:]    可显示的字符
[:punct:]    标点符号字符
[:xdigit:]    十六进制

示例:
 

在 Shell 下使用这些正则表达式处理文本最多的命令有下面几个工具:
命令    描述

grep    默认不支持扩展表达式,加-E 选项开启 ERE。如果不加-E 使用花括号要加 转义符\{\}
 
egrep    支持基础和扩展表达式
awk    支持 egrep 所有的正则表达式

sed    默认不支持扩展表达式,加-r 选项开启 ERE。如果不加-r 使用花括号要加 转义符\{\}

支持的特殊字符    描述
\w    匹配任意数字和字母,等效[a-zA-Z0-9_]
\W    与\w 相反,等效[^a-zA-Z0-9_]
\b    匹配字符串开始或结束,等效\<和\>
\s    匹配任意的空白字符
\S    匹配非空白字符

空白符    描述
\n    换行符
\r    回车符
\t    水平制表符
\v    垂直制表符
\0    空值符
\b    退后一格


第七章    Shell 文本处理三剑客

7.1    grep 过滤来自一个文件或标准输入匹配模式内容。
除了 grep 外,还有 egrep、fgrep。egrep 是 grep 的扩展,相当于 grep -E。fgrep 相当于 grep - f,用的少。
Usage: grep [OPTION]... PATTERN [FILE]...
支持的正则    描述
 
-E,--extended-regexp    模式是扩展正则表达式(ERE)
-P,--perl-regexp    模式是 Perl 正则表达式
-e,--regexp=PATTERN    使用模式匹配,可指定多个模式匹配
-f,--file=FILE    从文件每一行获取匹配模式
-i,--ignore-case    忽略大小写
-w,--word-regexp    模式匹配整个单词
-x,--line-regexp    模式匹配整行
-v,--invert-match    打印不匹配的行

输出控制    描述
-m,--max-count=NUM    输出匹配的结果 num 数
-n,--line-number    打印行号
-H,--with-filename    打印每个匹配的文件名
-h,--no-filename    不输出文件名
-o,--only-matching    只打印匹配的内容
-q,--quiet    不输出正常信息
-s, --no-messages    不输出错误信息
-r,--recursive    递归目录
-c,--count    只打印每个文件匹配的行数
--include=FILE_PATTERN
--exclude=FILE_PATTERN
--exclude-from=FILE
--exclude-dir=PATTERN    只检索匹配的文件 跳过匹配的文件 跳过匹配的文件,来自文件模式 跳过匹配的目录

内容行控制    描述
-B,--before-context=NUM    打印匹配的前几行
 
-A,--after-context=NUM    打印匹配的后几行
-C,--context=NUM    打印匹配的前后几行
--color[=WHEN],    匹配的字体颜色
示例:
1)输出 b 文件中在 a 文件相同的行
 
2)输出 b 文件中在 a 文件不同的行
 
3) 匹配多个模式
 
4)去除空格 http.conf 文件空行或开头#号的行
 
5) 匹配开头不分大小写的单词
 
6)只显示匹配的字符串
 
7)输出匹配的前五个结果
 
8)统计匹配多少行
 
9) 匹配 b 字符开头的行
 
 
 
10) 匹配 de 字符结尾的行并输出匹配的行
 
11) 递归搜索/etc 目录下包含 ip 的 conf 后缀文件
 
12) 排除搜索 bak 后缀的文件
 
13) 排除来自 file 中的文件
 
14) 匹配 41 或 42 的数字
 
15) 匹配至少 2 个字符
 
16) 匹配至少 2 个字符的单词,最多 3 个字符的单词
 
17) 匹配所有 IP
 
18) 打印匹配结果及后 319) 打印匹配结果及前 320) 打印匹配结果及前后 321) 不显示输出
 
grep 支持上一章的基础和扩展正则表达式字符。
7.2    sed 流编辑器,过滤和替换文本。
工作原理:sed 命令将当前处理的行读入模式空间进行处理,处理完把结果输出,并清空模式空 间。然后再将下一行读入模式空间进行处理输出,以此类推,直到最后一行。还有一个空间叫保持 空间,又称暂存空间,可以暂时存放一些处理的数据,但不能直接输出,只能放到模式空间输出。 这两个空间其实就是在内存中初始化的一个内存区域,存放正在处理的数据和临时存放的数据。 Usage:
sed [OPTION]... {script-only-if-no-other-script} [input-file]...
sed [选项] \'地址 命令\' file
选项    描述
-n    不打印模式空间
-e    执行脚本、表达式来处理
-f    执行动作从文件读取执行
-i    修改原文件
-r    使用扩展正则表达式
 
命令    描述
s/regexp/replacement/    替换字符串
p    打印当前模式空间
P    打印模式空间的第一行
d    删除模式空间,开始下一个循环
D    删除模式空间的第一行,开始下一个循环
=    打印当前行号
a \text    当前行追加文本
i \text    当前行上面插入文本
c \text    所选行替换新文本
q    立即退出 sed 脚本
r    追加文本来自文件
: label    label 为 b 和 t 命令
b label    分支到脚本中带有标签的位置,如果分支不存在则分支到脚本 的末尾
t label    如果 s///是一个成功的替换,才跳转到标签
h H    复制/追加模式空间到保持空间
g G    复制/追加保持空间到模式空间
x    交换模式空间和保持空间内容
l    打印模式空间的行,并显示控制字符$
n N    读取/追加下一行输入到模式空间
w filename    写入当前模式空间到文件
!    取反、否定
&    引用已匹配字符串
 
地址    描述
first~step    步长,每 step 行,从第 first 开始
$    匹配最后一行
/regexp/    正则表达式匹配行
number    只匹配指定行
addr1,addr2    开始匹配 addr1 行开始,直接 addr2 行结束
addr1,+N    从 addr1 行开始,向后的 N 行
addr1,~N    从 addr1 行开始,到 N 行结束

借助以下文本内容作为示例讲解:
# tail /etc/services
nimgtw    48003/udp    #    Nimbus Gateway
3gpp-cbsp    48049/tcp    #    3GPP Cell Broadcast Service Protocol
isnetserv    48128/tcp    #    Image Systems Network Services
isnetserv    48128/udp    #    Image Systems Network Services
blp5    48129/tcp    #    Bloomberg locator
blp5    48129/udp    #    Bloomberg locator
com-bardac-dw    48556/tcp    #    com-bardac-dw
com-bardac-dw    48556/udp    #    com-bardac-dw
iqobject    48619/tcp    #    iqobject
iqobject    48619/udp    #    iqobject

7.2.1  匹配打印(p)            

1)打印匹配 blp5 开头的行
 
2)打印第一行
 
3)打印第一行至第三行
 
 
4)打印奇数行
 
5)打印匹配行及后一行
# tail /etc/services blp5
blp5    |sed -n \'/blp5/,+1p\' 48129/tcp
48129/udp        
# Bloomberg locator
# Bloomberg locator
6)打印最后一行            
# tail /etc/services    |sed -n \'$p\'        
iqobject    48619/udp        # iqobject
7)不打印最后一行            
# tail /etc/services    |sed -n \'$!p\'        
3gpp-cbsp    48049/tcp    #    3GPP Cell Broadcast Service
Protocol            
isnetserv    48128/tcp    #    Image Systems Network Services
isnetserv    48128/udp    #    Image Systems Network Services
blp5    48129/tcp    #    Bloomberg locator
blp5    48129/udp    #    Bloomberg locator
com-bardac-dw    48556/tcp    #    com-bardac-dw
com-bardac-dw    48556/udp    #    com-bardac-dw
iqobject    48619/tcp    #    iqobject
iqobject    48619/udp    #    iqobject
感叹号也就是对后面的命令取反。
8)匹配范围
 
匹配开头行到最后一行:
 
以逗号分开两个样式选择某个范围。
9)引用系统变量,用引号
 
 
sed 命令用单引号时,里面变量用单引号引起来,或者 sed 命令用双引号,因为双引号解释特殊符
号原有意义。

7.2.2 匹配删除(d) 删除与打印使用方法类似,简单举几个例子。









































去除空格 http.conf 文件空行或开头#号的行:
 
 

打印是把匹配的打印出来,删除是把匹配的删除,删除只是不用-n 选项。 7.2.3  替换(s///1)替换 blp5 字符串为 test
 
2)替换开头是 blp5 的字符串并打印
 
3)使用&命令引用匹配内容并替换
# tail /etc/services |sed \'s/48049/&.0/\'
3gpp-cbsp    48049.0/tcp    #    3GPP Cell Broadcast Service
isnetserv    48128/tcp    #    Image Systems Network Services
isnetserv    48128/udp    #    Image Systems Network Services
blp5    48129/tcp    #    Bloomberg locator
blp5    48129/udp    #    Bloomberg locator
com-bardac-dw    48556/tcp    #    com-bardac-dw
com-bardac-dw    48556/udp    #    com-bardac-dw
iqobject    48619/tcp    #    iqobject
iqobject    48619/udp    #    iqobject
matahari    49000/tcp    #    Matahari Broker
IP 加单引号:            
# echo \'10.10.10.1 10.10.10.2 10.10.10.3\' |sed -r \'s/[^ ]+/"&"/g\'
"10.10.10.1" "10.10.10.2" "10.10.10.3"
4)对 1-4 行的 blp5 进行替换
 
 
 
5)对匹配行进行替换
 
6)二次匹配替换
 
7)分组使用,在每个字符串后面添加 123
 
 
 
第一列是第一个小括号匹配,第二列第二个小括号匹配,第三列一样。将不变的字符串匹配分组,
再通过\数字按分组顺序反向引用。 8)将协议与端口号位置调换
# tail /etc/services |sed -r \'s/(.*)(\<[0-9]+\>)\/(tcp|udp)(.*)/\1\3\/\2\4/\'
3gpp-cbsp    tcp/48049    #    3GPP Cell Broadcast Service
isnetserv    tcp/48128    #    Image Systems Network Services
isnetserv    udp/48128    #    Image Systems Network Services
blp5    tcp/48129    #    Bloomberg locator
blp5    udp/48129    #    Bloomberg locator
com-bardac-dw    tcp/48556    #    com-bardac-dw
com-bardac-dw    udp/48556    #    com-bardac-dw
iqobject    tcp/48619    #    iqobject
iqobject    udp/48619    #    iqobject
matahari    tcp/49000    #    Matahari Broker
9)位置调换            
替换 x 字符为大写:
# echo "abc cde xyz" |sed -r \'s/(.*)x/\1X/\' abc cde Xyz
456 与 cde 调换:
# echo "abc:cde;123:456" |sed -r \'s/([^:]+)(;.*:)([^:]+$)/\3\2\1/\' abc:456;123:cde
10)注释匹配行后的多少行
 
11)注释指定多行
 
 
 
12)去除开头和结尾空格或制表符
 

7.2.4 多重编辑(-e)

 
也可以使用分号分隔:
 

7.2.5 添加新内容(a、i 和 c)

1)在 blp5 上一行添加 test
 
 
matahari    49000/tcp    #    Matahari Broker
2)在 blp5 下一行添加 test        
# tail /etc/services |sed \'/blp5/a \test\'        
3gpp-cbsp    48049/tcp    #    3GPP Cell Broadcast Service
isnetserv    48128/tcp    #    Image Systems Network Services
isnetserv    48128/udp    #    Image Systems Network Services
blp5    48129/tcp    #    Bloomberg locator
test        
blp5    48129/udp    #    Bloomberg locator
test        
com-bardac-dw    48556/tcp    #    com-bardac-dw
com-bardac-dw    48556/udp    #    com-bardac-dw
iqobject    48619/tcp    #    iqobject
iqobject    48619/udp    #    iqobject
matahari    49000/tcp    #    Matahari Broker
3)将 blp5 替换新行        
# tail /etc/services |sed \'/blp5/c \test\'        
3gpp-cbsp    48049/tcp    #    3GPP Cell Broadcast Service
isnetserv    48128/tcp    #    Image Systems Network Services
isnetserv    48128/udp    #    Image Systems Network Services
test        
test        
com-bardac-dw    48556/tcp    #    com-bardac-dw
com-bardac-dw    48556/udp    #    com-bardac-dw
iqobject    48619/tcp    #    iqobject
iqobject    48619/udp    #    iqobject
matahari    49000/tcp    #    Matahari Broker
4)在指定行下一行添加一行        
# tail /etc/services |sed \'2a \test\'        
3gpp-cbsp    48049/tcp    #    3GPP Cell Broadcast Service
isnetserv    48128/tcp    #    Image Systems Network Services
test        
isnetserv    48128/udp    #    Image Systems Network Services
blp5    48129/tcp    #    Bloomberg locator
blp5    48129/udp    #    Bloomberg locator
com-bardac-dw    48556/tcp    #    com-bardac-dw
com-bardac-dw    48556/udp    #    com-bardac-dw
iqobject    48619/tcp    #    iqobject
iqobject    48619/udp    #    iqobject
matahari    49000/tcp    #    Matahari Broker
5)在指定行前面和后面添加一行
 
 
 

7.2.6 读取文件并追加到匹配行后(r)

 

7.2.7 将匹配行写到文件(w)

 
 
 

7.2.8 读取下一行(n 和 N)

n 读取下一行到模式空间。
N 追加下一行内容到模式空间,并以换行符\n 分隔。 1)打印匹配的下一行
 
2)打印偶数
 
 
sed 先读取第一行 1,执行 n 命令,获取下一行 2,此时模式空间是 2,执行 p 命令,打印模式空
间。 现在模式空间是 2,sed 再读取 3,执行 n 命令,获取下一行 4,此时模式空间为 4,执行 p 命 令,以此类推。
3)打印奇数
 
sed 先读取第一行 1,此时模式空间是 1,并打印模式空间 1,执行 n 命令,获取下一行 2,执行 d
命令,删除模式空间的 2,sed 再读取 3,此时模式空间是 3,并打印模式空间,再执行 n 命令,获 取下一行 4,执行 d 命令,删除模式空间的 3,以此类推。
 
4)每三行执行一次 p 命令
 
 
 
sed 先读取第一行 1,并打印模式空间 1,执行 n 命令,获取下一行 2,并打印模式空间 2,再执行 n
命令,获取下一行 3,执行 p 命令,打印模式空间 3。sed 读取下一行 3,并打印模式空间 3,以此类 推。
5)每三行替换一次 方法 1:
 
我们只是把 p 命令改成了替换命令。
方法 2: 这次用到了地址匹配,来实现上面的效果:
 
当执行多个 sed 命令时,有时相互会产生影响,我们可以用大括号{}把他们括起来。
6)再看下 N 命令的功能
 
第一个命令:sed 读取第一行 1,N 命令读取下一行 2,并以\n2 追加,此时模式空间是 1\n2,再执
行 q 退出。
为了进一步说明 N 的功能,看第二个命令:执行 N 命令后,此时模式空间是 1\n2,再执行把\n 替换 为空,此时模式空间是 12,并打印。
 
 
 
为什么第一个不打印 5 呢?
因为 N 命令是读取下一行追加到 sed 读取的当前行,当 N 读取下一行没有内容时,则退出,也不会 执行 p 命令打印当前行。
当行数为偶数时,N 始终就能读到下一行,所以也会执行 p 命令。 7)打印奇数行数时的最后一行
 
加一个满足条件,当 sed 执行到最后一行时,用感叹号不去执行 N 命令,随后执行 p 命令。
7.2.9 打印和删除模式空间第一行(P 和 D) P 打印模式空间的第一行。
D 删除模式空间的第一行。 1)打印奇数
 
2)保留最后一行
 
读取第一行 1,执行 N 命令读取下一行并追加到模式空间,此时模式空间是 1\n2,执行 D 命令删除
模式空间第一行 1,剩余 2。
读取第二行,执行 N 命令,此时模式空间是 3\n4,执行 D 命令删除模式空间第一行 3,剩余 4。 以此类推,读取最后一行打印时,而 N 获取不到下一行则退出,不再执行 D,因此模式空间只剩余 6 就打印。

7.2.10  保持空间操作(h 与 H、g 与 G 和 x)

h 复制模式空间内容到保持空间(覆盖)。 H 复制模式空间内容追加到保持空间。
g 复制保持空间内容到模式空间(覆盖)。 G 复制保持空间内容追加到模式空间。
x 模式空间与保持空间内容互换 1)将匹配的内容覆盖到另一个匹配
 
 
h 命令把匹配的 3 复制到保持空间,d 命令删除模式空间的 3。后面命令再对模式空间匹配 5,并用
g 命令把保持空间 3 覆盖模式空间 5。 2)将匹配的内容放到最后
 
3)交换模式空间和保持空间
 
看后面命令,在模式空间匹配 5 并将保持空间的 3 与 5 交换,5 就变成了 3,。最后把保持空间的 5
追加到模式空间的。 4)倒叙输出
 
分析下:
1!G 第一行不执行把保持空间内容追加到模式空间,因为现在保持空间还没有数据。 h 将模式空间放到保持空间暂存。
$!d 最后一行不执行删除模式空间的内容。
读取第一行 1 时,跳过 G 命令,执行 h 命令将模式空间 1 复制到保持空间,执行 d 命令删除模式空 间的 1。
读取第二行 2 时,模式空间是 2,执行 G 命令,将保持空间 1 追加到模式空间,此时模式空间是
2\n1,执行 h 命令将 2\n1 覆盖到保持空间,d 删除模式空间。
读取第三行 3 时,模式空间是 3,执行 G 命令,将保持空间 2\n1 追加到模式空间,此时模式空间是 3\n2\n1,执行 h 命令将模式空间内容复制到保持空间,d 删除模式空间。
 
以此类推,读到第 5 行时,模式空间是 5,执行 G 命令,将保持空间的 4\n3\n2\n1 追加模式空间, 然后复制到模式空间,5\n4\n3\n2\n1,不执行 d,模式空间保留,输出。 由此可见,每次读取的行先放到模式空间,再复制到保持空间,d 命令删除模式空间内容,防止输 出,再追加到模式空间,因为追加到模式空间,会追加到新读取的一行的后面,循环这样操作, 就 把所有行一行行追加到新读取行的后面,就形成了倒叙。
5)每行后面添加新空行
 
6)打印匹配行的上一行内容
 
读取第一行 1,没有匹配到 3,不执行{x;p},执行 h 命令将模式空间内容 1 覆盖到保持空间。
读取第二行 2,没有匹配到 3,不执行{x;p},执行 h 命令将模式空间内容 2 覆盖到保持空间。 读取第三行 3,匹配到 3,执行 x 命令把模式空间 3 与保持空间 2 交换,再执行 p 打印模式空间 2. 以此类推。
7)打印匹配行到最后一行或下一行到最后一行
 
匹配到 3 时,n 读取下一行 4,此时模式空间是 4,执行 N 命令读取下一行并追加到模式空间,此时
模式空间是 4\n5,标签循环完成后打印模式空间 4\n5。 7.2.11 标签(:、b 和 t) 标签可以控制流,实现分支判断。
 
: lable name    定义标签
b lable    跳转到指定标签,如果没有标签则到脚本末尾 t lable    跳转到指定标签,前提是 s///命令执行成功 1)将换行符替换成逗号
方法 1:
 
这种方式并不能满足我们的需求,每次 sed 读取到模式空间再打印是新行,替换\n 也只能对 N 命令
追加后的 1\n2 这样替换。 这时就可以用到标签了:
 
看看这里的标签使用,:a 是定义的标签名,b a 是跳转到 a 位置。
sed 读取第一行 1,N 命令读取下一行 2,此时模式空间是 1\n2$,执行替换,此时模式空间是 1,2$,执行 b 命令再跳转到标签 a 位置继续执行 N 命令,读取下一行 3 追加到模式空间,此时模式 空间是 1,2\n3$,再替换,以此类推,不断追加替换,直到最后一行 N 读不到下一行内容退出。 方法 2:
 
先将每行读入到模式空间,最后再执行全局替换。$!是如果是最后一行,则不执行 b a 跳转,最后
执行全局替换。
 
可以看到,不加$!是没有替换,因为循环到 N 命令没有读到行就退出了,后面的替换也就没执行。
2)每三个数字加个一个逗号
 
执行第一次时,替换最后一个,跳转后,再对 123456 匹配替换,直到匹配替换不成功,不执行 t 命
令。
 
7.2.12  忽略大小写匹配(I)

 

7.2.13  获取总行数(#

 

8.3 awk

awk 是一个处理文本的编程语言工具,能用简短的程序处理标准输入或文件、数据排序、计算以及 生成报表等等。
在 Linux 系统下默认 awk 是 gawk,它是 awk 的 GNU 版本。可以通过命令查看应用的版本:ls -l
/bin/awk
基本的命令语法:awk option \'pattern {action}\' file
其中 pattern 表示 AWK 在数据中查找的内容,而 action 是在找到匹配内容时所执行的一系列命令。 花括号用于根据特定的模式对一系列指令进行分组。
awk 处理的工作方式与数据库类似,支持对记录和字段处理,这也是 grep 和 sed 不能实现的。 在 awk 中,缺省的情况下将文本文件中的一行视为一个记录,逐行放到内存中处理,而将一行中的 某一部分作为记录中的一个字段。用 1,2,3...数字的方式顺序的表示行(记录)中的不同字段。用
$后跟数字,引用对应的字段,以逗号分隔,0 表示整个行。

 
 
8.3.1 选项

选项    描述
-f program-file    从文件中读取 awk 程序源文件
-F fs    指定 fs 为输入字段分隔符
-v var=value    变量赋值
--posix    兼容 POSIX 正则表达式
--dump-variables=[file]    把 awk 命令时的全局变量写入文件, 默认文件是 awkvars.out
--profile=[file]    格式化 awk 语句到文件,默认是 awkprof.out

8.3.2 模式

常用模式有:
Pattern    Description
BEGIN{ }    给程序赋予初始状态,先执行的工作
END{ }    程序结束之后执行的一些扫尾工作
/regular expression/    为每个输入记录匹配正则表达式
pattern && pattern    逻辑 and,满足两个模式
pattern || pattern    逻辑 or,满足其中一个模式
! pattern    逻辑 not,不满足模式
pattern1, pattern2    范围模式,匹配所有模式 1 的记录,直到匹配到模式 2
而动作呢,就是下面所讲的 print、流程控制、I/O 语句等。 示例:
1)从文件读取 awk 程序处理文件
 
2)指定分隔符,打印指定字段
 
 
还可以指定多个分隔符,作为同一个分隔符处理:
 
[]元字符的意思是符号其中任意一个字符,也就是说每遇到一个/或#时就分隔一个字段,当用多个
分隔符时,就能更方面处理字段了。 3)变量赋值
 
 
 
4)输出 awk 全局变量到文件
 
5)BEGIN 和 END
BEGIN 模式是在处理文件之前执行该操作,常用于修改内置变量、变量赋值和打印输出的页眉或标 题。
例如:打印页眉
 
 
 
END 模式是在程序处理完才会执行。
例如:打印页尾
 
6)格式化输出 awk 命令到文件
 
 
 
7)/re/正则匹配
 
8)逻辑 andornot
 
 
 
9)匹配范围
 
对匹配范围后记录再次处理,例如匹配关键字下一行到最后一行:
 

8.3.3 内置变量

变量名    描述
FS    输入字段分隔符,默认是空格或制表符
OFS    输出字段分隔符,默认是空格
RS    输入记录分隔符,默认是换行符\n
ORS    输出记录分隔符,默认是换行符\n
NF    统计当前记录中字段个数
NR    统计记录编号,每处理一行记录,编号就会+1
FNR    统计记录编号,每处理一行记录,编号也会+1,与 NR 不同的是,处理第二个 文件时,编号会重新计数。
ARGC    命令行参数数量
 
ARGV    命令行参数数组序列数组,下标从 0 开始,ARGV[0]是 awk
ARGIND    当前正在处理的文件索引值。第一个文件是 1,第二个文件是 2,以此类推
ENVIRON    当前系统的环境变量
FILENAME    输出当前处理的文件名
IGNORECASE    忽略大小写
SUBSEP    数组中下标的分隔符,默认为"\034"
示例:
1)FS 和 OFS
在程序开始前重新赋值 FS 变量,改变默认分隔符为冒号,与-F 一样。
 
2)RS 和 ORS
RS 默认是\n 分隔每行,如果想指定以某个字符作为分隔符来处理记录:
 
 
 
3)NF
NF 是字段个数。
 
4)NR 和 FNR
NR 统计记录编号,每处理一行记录,编号就会+1,FNR 不同的是在统计第二个文件时会重新计数。
 
 
 
看下 NR 和 FNR 的区别:
 
可以看出 NR 每处理一行就会+1,而 FNR 在处理第二个文件时,编号重新计数。同时也知道 awk 处理
两个文件时,是合并到一起处理。
 
当 FNR==NR 时,说明在处理第一个文件内容,不等于时说明在处理第二个文件内容。
一般 FNR 在处理多个文件时会用到,下面会讲解。 5)ARGC 和 ARGV
ARGC 是命令行参数数量
ARGV 是将命令行参数存到数组,元素由 ARGC 指定,数组下标从 0 开始
 
 
 
6)ARGIND
ARGIND 是当前正在处理的文件索引值,第一个文件是 1,第二个文件是 2,以此类推,从而可以通 过这种方式判断正在处理哪个文件。
 
7)ENVIRON
ENVIRON 调用系统变量。
 
8)FILENAME
FILENAME 是当前处理文件的文件名。
 
等于 1 代表忽略大小写。
 
8.3.4 操作符

运算符    描述
(....)    分组
$    字段引用
++ --    递增和递减
+ - !    加号,减号,和逻辑否定
* / %    乘,除和取余
+ -    加法,减法
| |&    管道,用于 getline,print 和 printf
< > <= >= != ==    关系运算符
~ !~    正则表达式匹配,否定正则表达式匹配
in    数组成员
&& ||    逻辑 and,逻辑 or
?:    简写条件表达式: expr1 ? expr2 : expr3
第一个表达式为真,执行 expr2,否则执行 expr3
= += -= *= /= %= ^=    变量赋值运算符
须知:
在 awk 中,有 3 种情况表达式为假:数字是 0,空字符串和未定义的值。 数值运算,未定义变量初始值为 0。字符运算,未定义变量初始值为空。 举例测试:
 
示例:
1)截取整数
 
 
 
2)感叹号
 
读取第一行:i 是未定义变量,也就是 i=!0,!取反意思。感叹号右边是个布尔值,0 或空字符串为
假,非 0 或非空字符串为真,!0 就是真,因此 i=1,条件为真打印当前记录。 没有 print 为什么会打印呢?因为模式后面没有动作,默认会打印整条记录。 读取第二行:因为上次 i 的值由 0 变成了 1,此时就是 i=!1,条件为假不打印。 读取第三行:上次条件又为假,i 恢复初始值 0,取反,继续打印。以此类推... 可以看出,运算时并没有判断行内容,而是利用布尔值真假判断输出当前行。

2)不匹配某行    
# tail /etc/services |awk \'!/blp5/{print    $0}\'        
3gpp-cbsp    48049/tcp        #    3GPP Cell Broadcast Service
isnetserv    48128/tcp        #    Image Systems Network Services
isnetserv    48128/udp        #    Image Systems Network Services
com-bardac-dw    48556/tcp        #    com-bardac-dw
com-bardac-dw    48556/udp        #    com-bardac-dw
iqobject    48619/tcp        #    iqobject
iqobject    48619/udp        #    iqobject
matahari    49000/tcp        #    Matahari Broker
3)乘法和除法            
# seq 5 |awk \'{print $0*2}\' 2
4
6
8
10
# seq 5 |awk \'{print $0%2}\' 1
0
1
 
 
4)管道符使用
 
5)正则表达式匹配
 
6)判断数组成员
 
7)三目运算符
 
 

no yes no
替换换行符为逗号:
# seq 5 |awk \'{print n=(n?n","$0:$0)}\' 1
1,2
1,2,3
1,2,3,4
1,2,3,4,5
# seq 5 |awk \'{n=(n?n","$0:$0)}END{print n}\' 1,2,3,4,5
说明:读取第一行时,n 没有变量,为假输出$0 也就是 1,并赋值变量 n,读取第二行时,n 是 1 为 真,输出 1,2 以此类推,后面会一直为真。
每三行后面添加新一行:
# seq 10 |awk \'{print NR%3?$0:$0 "\ntxt"}\' 1
2
3
txt 4
5
6
txt 7
8
9
txt 10
在 两行合并一行:
# seq 6 |awk \'{printf NR%2!=0?$0" ":$0" \n"}\' 1 2
3 4
5 6
# seq 6 |awk \'ORS=NR%2?" ":"\n"\' 1 2
3 4
5 6
# seq 6 |awk \'{if(NR%2)ORS=" ";else ORS="\n";print}\'

8)变量赋值
 
 
8.3.5 流程控制

1)if 语句
格式:if (condition) statement [ else statement ]
 
2)while 语句
格式:while (condition) statement
 
 
3)for 语句 C 语言风格
格式:for (expr1; expr2; expr3) statement

遍历打印所有字段:
# cat file 1 2 3
4 5 6
7 8 9
# awk \'{for(i=1;i<=NF;i++)print $i}\' file 1
2
3
4
5
6
7
8
9
倒叙打印文本:
# awk \'{for(i=NF;i>=1;i--)print $i}\' file 3
2
1
6
5
4
9
8
7
都换行了,这并不是我们要的结果。怎么改进呢?
# awk \'{for(i=NF;i>=1;i--){printf $i" "};print ""}\' file    # print 本身就会新打印一行 3 2 1
6 5 4
9 8 7# awk \'{for(i=NF;i>=1;i--)if(i==1)printf $i"\n";else printf $i" "}\' file 3 2 1
6 5 4
9 8 7
在这种情况下,是不是就排除第一行和倒数第一行呢?我们正序打印看下 排除第一行:
# awk \'{for(i=2;i<=NF;i++){printf $i" "};print ""}\' file 2 3
5 6
8 9
排除第二行:
# awk \'{for(i=1;i<=NF-1;i++){printf $i" "};print ""}\' file 1 2
4 5
 
 
4)for  语句遍历数组
格式:for (var in array) statement
 
5)breakcontinue 语句
break 跳过所有循环,continue 跳过当前循环。
 
6)删除数组和元素
格式:
delete array[index]    删除数组元素 delete array    删除数组
 
7)exit 语句
格式:exit [ expression ]
exit 退出程序,与 shell 的 exit 一样。[ expr ]是 0-255 之间的数字。
 
 
8.3.6 数组

数组:存储一系列相同类型的元素,键/值方式存储,通过下标(键)来访问值。  awk 中数组称为关联数组,不仅可以使用数字作为下标,还可以使用字符串作为下标。
数组元素的键和值存储在 awk 程序内部的一个表中,该表采用散列算法,因此数组元素是随机排 序。
数组格式:array[index]=value 1)自定义数组
 
3)通过 for 循环遍历数组
 
上面打印的 i 是数组的下标。
第一种 for 循环的结果是乱序的,刚说过,数组是无序存储。 第二种 for 循环通过下标获取的情况是排序正常。
所以当下标是数字序列时,还是用 for(expr1;expr2;expr3)循环表达式比较好,保持顺序不变。 4)通过++方式作为下标
 
x 被 awk 初始化值是 0,没循环一次+1
5)使用字段作为下标
 
 
 
6)统计相同字段出现次数
 
第一个字段作为下标,值被++初始化是 0,每次遇到下标(第一个字段)一样时,对应的值就会被
+1,因此实现了统计出现次数。 想要实现去重的的话就简单了,只要打印下标即可。 7)统计 TCP 连接状态
 
8)只打印出现次数大于等于 29)去重
 
 
# tail /etc/services |awk \'!a[$1]++\'
3gpp-cbsp    48049/tcp    #    3GPP Cell Broadcast Service
isnetserv    48128/tcp    #    Image Systems Network Services
blp5    48129/tcp    #    Bloomberg locator
com-bardac-dw    48556/tcp    #    com-bardac-dw
iqobject    48619/tcp    #    iqobject
matahari    49000/tcp    #    Matahari Broker
先明白一个情况,当值是 0 是为假,非 0 整数为真,知道这点就不难理解了。
只打印重复的行说明:当处理第一条记录时,执行了++,初始值是 0 为假,就不打印,如果再遇到 相同的记录,值就会+1,不为 0,则打印。 不打印重复的行说明:当处理第一条记录时,执行了++,初始值是 0 为假,感叹号取反为真,打
印,如果再遇到相同的记录,值就会+1,不为 0 为真,取反为假就不打印。
 
10)统计每个相同字段的某字段总数:
 
11)多维数组
 
awk 的多维数组,实际上 awk 并不支持多维数组,而是逻辑上模拟二维数组的访问方式,比如 a[a,b]=1,使用 SUBSEP(默认\034)作为分隔下标字段,存储后是这样 a\034b。
示例:
 

8.3.7 内置函数

函数    描述
int(expr)    截断为整数
sqrt(expr)    平方根
rand()    返回一个随机数 N,0 和 1 范围,0 < N < 1

srand([expr])    使用 expr 生成随机数,如果不指定,默认使用当前时间为种子,如 果前面有种子则使用生成随机数

asort(a, b)    对数组 a 的值进行排序,把排序后的值存到新的数组 b 中,新排序 的数组下标从 1 开始
asorti(a,b)    对数组 a 的下标进行排序,同上

sub(r, s [, t])    对输入的记录用 s 替换 r 正则匹配,t 可选针对某字段替换,但只替 换第一个字符串

gsub(r, s [, t])    对输入的记录用 s 替换 r 正则匹配,t 可选针对某字段替换,否则替 换所有字符串
 
gensub(r, s, h [, t])    对输入的记录用 s 替换 r 正则匹配,h 替换指定索引位置
index(s, t)    返回 s 中字符串 t 的索引位置,0 为不存在
length([s])    返回 s 的长度
match(s, r [, a])    测试字符串 s 是否包含匹配 r 的字符串,如果不包含返回 0
split(s, a [, r [, seps] ])    
根据分隔符 seps 将 s 分成数组 a
substr(s, i [, n])    截取字符串 s 从 i 开始到长度 n,如果 n 没指定则是剩余部分
tolower(str)    str 中的所有大写转换成小写
toupper(str)    str 中的所有小写转换成大写
systime()    当前时间戳
strftime([format [, timestamp[, utc- flag]]])    
格式化输出时间,将时间戳转为字符串
示例:
1)int()
 
2)sqrt()
 
3)rand()和 srand()
 
 
 
如果想更完美生成随机数,还得做相应的处理!
4)asort()和 asorti()
 
asort 将 a 数组的值放到数组 b,a 下标丢弃,并将数组 b 的总行号赋值给 s,新数组 b 下标从 1 开
始,然后遍历。 5)sub()和 gsub()
 
在指定行前后加一行:
 
 
 
6)index()
 
7)length()
 
8)match
 
9)split()
 
 
 
10)substr()
 
11)tolower()和 toupper()
 
12)时间处理
 

8.3.8  I/O 语句

语句    描述
getline    读取下一个输入记录设置给$0
getline var    读取下一个输入记录并赋值给变量 var
command | getline [var]    运行 Shell 命令管道输出到$0 或 var
next    停止当前处理的输入记录后面动作
print    打印当前记录
printf fmt, expr-list    格式化输出
 
printf fmt, expr-list >file    格式输出和写到文件
system(cmd-line)    执行命令和返回状态
print ... >> file    追加输出到文件
print ... | command    打印输出作为命令输入
示例:
1)getline
 
2)getline var
 
 
 
3)command | getline [var]
 
4)next
 
 
 
5)system()
 
6)打印结果写到文件
 
7)管道连接 shell 命令
 

8.3.9 printf 语句

格式化输出,默认打印字符串不换行。 格式:printf [format]    arguments
Format    描述
%s    一个字符串
%d,%i    一个小数
%f    一个浮点数
%.ns    输出字符串,n 是输出几个字符
%m.nf    输出浮点数,m 是输出整数位数,n 是输出的小数位数
%x    不带正负号的十六进制,使用 a 至 f 表示 10 到 15
%X    不带正负号的十六进制,使用 A 至 F 表示 10 至 15
%%    输出单个%
 
%-5s    左对齐,对参数每个字段左对齐,宽度为 5
%-4.2f    左对齐,宽度为 4,保留两位小数
%5s    右对齐,不加横线表示右对齐
示例:

将换行符换成逗号:
# seq 5 |awk \'{if($0!=5)printf "%s,",$0;else print $0}\' 1,2,3,4,5
小括号中的 5 是最后一个数字。 输出一个字符:
# awk \'BEGIN{printf "%.1s\n","abc"}\' a
保留一个小数点:
# awk \'BEGIN{printf "%.2f\n",10/3}\' 3.33
格式化输出:
# awk \'BEGIN{printf "user:%s\tpass:%d\n","abc",123}\' user:abc    pass:123
左对齐宽度 10# awk \'BEGIN{printf "%-10s %-10s %-10s\n","ID","Name","Passwd"}\'
ID    Name    Passwd 右对齐宽度 10# awk \'BEGIN{printf "%10s %10s %10s\n","ID","Name","Passwd"}\' ID    Name    Passwd
打印表格:
# vi test.awk BEGIN{
print "+--------------------+--------------------+";
printf "|%-20s|%-20s|\n","Name","Number";
print "+--------------------+--------------------+";
}
# awk -f test.awk
+--------------------+--------------------+
|Name    |Number    |
+--------------------+--------------------+
格式化输出:
# awk -F: \'BEGIN{printf "UserName\t\tShell\n-----------------------------\n"}{printf "%-20s %-20s\n",$1,$7}END{print "END...\n"}\' /etc/passwd
打印十六进制:
# awk \'BEGIN{printf "%x %X",123,123}\' 7b 7B


8.3.10 自定义函数

格式:function name(parameter list) { statements }
 
示例:
 

8.3.11 需求案例

1)分析 Nginx 日志 日志格式:
\'$remote_addr    -    $remote_user    [$time_local]    "$request"    $status    $body_bytes_sent    "
$http_referer"    "$http_user_agent"    "$http_x_forwarded_for"\'

统计访问 IP 次数:
# awk \'{a[$1]++}END{for(v in a)print v,a[v]}\' access.log 统计访问访问大于 100 次的 IP:
# awk \'{a[$1]++}END{for(v in a){if(a[v]>100)print v,a[v]}}\' access.log 统计访问 IP 次数并排序取前 10:
# awk \'{a[$1]++}END{for(v in a)print v,a[v] |"sort -k2 -nr |head -10"}\' access.log 统计时间段访问最多的 IP:
# awk \'$4>="[02/Jan/2017:00:02:00" && $4<="[02/Jan/2017:00:03:00"{a[$1]++}END{for(v in
a)print v,a[v]}\' access.log 统计上一分钟访问量:
#    date=$(date -d \'-1 minute\' +%d/%d/%Y:%H:%M)
# awk -vdate=$date \'$4~date{c++}END{print c}\' access.log 统计访问最多的 10 个页面:
#    awk    \'{a[$7]++}END{for(v in    a)print v,a[v] |"sort    -k1    -nr|head    - n10"}\'    access.log
统计每个 URL 数量和返回内容总大小:
# awk \'{a[$7]++;size[$7]+=$10}END{for(v in a)print a[v],v,size[v]}\' access.log 统计每个 IP 访问状态码数量:
# awk \'{a[$1" "$9]++}END{for(v in a)print v,a[v]}\' access.log 统计访问 IP 是 404 状态次数:
# awk    \'{if($9~/404/)a[$1"    "$9]++}END{for(i    in    a)print v,a[v]}\'    access.log

2)两个文件对比
找出 b 文件在 a 文件相同记录:
 
 
 
找出 b 文件在 a 文件不同记录:
 
3)合并两个文件
将 a 文件合并到 b 文件:
 
 
 
将 a 文件相同 IP 的服务名合并:
 
说明:数组 a 存储是$1=a[$1] $2,第一个 a[$1]是以第一个字段为下标,值是 a[$1] $2,也就是
$1=a[$1] $2,值的 a[$1]是用第一个字段为下标获取对应的值,但第一次数组 a 还没有元素,那么 a[$1]是空值,此时数组存储是 192.168.1.1=httpd,再遇到 192.168.1.1 时,a[$1]通过第一字段 下标获得上次数组的 httpd,把当前处理的行第二个字段放到上一次同下标的值后面,作为下标 192.168.1.1 的新值。此时数组存储是 192.168.1.1=httpd tomcat。每次遇到相同的下标(第一个 字段)就会获取上次这个下标对应的值与当前字段并作为此下标的新值。  4)将第一列合并到一行
 
说明:
for 循环是遍历每行的字段,NF 等于 3,循环 3 次。 读取第一行时:
第一个字段:a[1]=a[1]1" "    值 a[1]还未定义数组,下标也获取不到对应的值,所以为空,因此 a[1]=1 。
第二个字段:a[2]=a[2]2" "    值 a[2]数组 a 已经定义,但没有 2 这个下标,也获取不到对应的 值,为空,因此 a[2]=2 。
第三个字段:a[3]=a[3]3" "    值 a[2]与上面一样,为空,a[3]=3 。 读取第二行时:
第一个字段:a[1]=a[1]4" "    值 a[2]获取数组 a 的 2 为下标对应的值,上面已经有这个下标了,
对应的值是 1,因此 a[1]=1 4 第二个字段:a[2]=a[2]5" "    同上,a[2]=2 5 第三个字段:a[3]=a[3]6" "    同上,a[2]=3 6
 
读取第三行时处理方式同上,数组最后还是三个下标,分别是 1=1 4 7,2=2 5 8,3=3 6 9。最后 for 循环输出所有下标值。
5)字符串拆分,统计出现的次数 字符串拆分:
 
统计字符串中每个字母出现的次数:
 
6)统计平均成绩
 
7)费用统计
 
 




zhaoliu    6000    1
zhaoliu    2000    1
zhaoliu    3000    1







8)获取数字字段最大值


a    b    1
c    d    2
e    f    3
g    h    3
i    j    2






g    h    3    3    3
e    f    3    3    3
c    d    2    2    3
a    b    1    1    3
i    j    2    2    3




9)去除第一行和最后一行
 
读取第一行,NR=1,不执行 print s,s=1
读取第二行,NR=2,不执行 print s,s=2 (大于为真) 读取第三行,NR=3,执行 print s,此时 s 是上一次 p 赋值内容 2,s=3 最后一行,执行 print s,打印倒数第二行,s=最后一行
获取 Nginx 负载均衡配置端 IP 和端口:
 
 
读取第一行,i 初始值为 0,0>1 为假,不执行 print s,x=example-servers1,i=1
读取第二行,i=1,1>1 为假,不执行 print s,s=127.0.0.1:80,i=2
读取第三行,i=2,2>1 为真,执行 print s,此时 s 是上一次 s 赋值内容 127.0.0.1:80,i=3 最后一行,执行 print s,打印倒数第二行,s=最后一行。
这种方式与上面一样,只是用 i++作为计数器。 10)知道上述方式,就可以实现这种需求了,打印匹配行的上一行
 

其他参考资料:http://www.gnu.org/software/gawk/manual/gawk.html


第八章    Shell 标准输入、输出和错误

文件描述符(fd):文件描述符是一个非负整数,在打开现存文件或新建文件时,内核会返回一个 文件描述符,读写文件也需要使用文件描述符来访问文件。 内核为每个进程维护该进程打开的文件记录表。文件描述符只适于 Unix、Linux 操作系统。

8.1 标准输入、输出和错误

文件描述符    描述    映射关系
0    标准输入,键盘    /dev/stdin -> /proc/self/fd/0
1    标准输出,屏幕    /dev/stdout -> /proc/self/fd/1
2    标准错误,屏幕    /dev/stderr -> /proc/self/fd/2

8.2 重定向符号

符号    描述
>    符号左边输出作为右边输入(标准输出)
 
>>    符号左边输出追加右边输入
<    符号右边输出作为左边输入(标准输入)
<<    符号右边输出追加左边输入
&    重定向绑定符号
输入和输出可以被重定向符号解释到 shell。
shell 命令是从左到右依次执行命令。 下面 n 字母是文件描述符。
8.3 重定向输出

1)覆盖输出 一般格式:[n]>word
如果 n 没有指定,默认是 1 示例:
 
2)追加重定向输出
一般格式:[n]>>word 如果 n 没有指定,默认是 1 示例:
 

8.4 重定向输入

一般格式:[n]<word
如果 n 没有指定,默认是 0 示例:
 

8.5   重定向标准输出和标准错误

1)覆盖重定向标准输出和标准错误 &>word 和>&word 等价于 >word 2>&1
 
&将标准输出和标准输入绑定到一起,重定向 word 文件。 示例:
 
2)追加重定向标准输出和标准错误
&>>word 等价于>>word 2>&1 示例:
 
将标准输出和标准输入追加重定向到 delimiter:
 
从当前 shell 读取输入源,直到遇到一行只包含 delimiter 终止,内容作为标准输入。
将 eof 标准输入作为 cat 标准输出再写到 a.txt:
 

8.6 重定向到空设备

/dev/null 是一个空设备,向它写入的数组都会丢弃,但返回状态是成功的。与其对应的还有一个
/dev/zero 设备,提供无限的 0 数据流。
在写 Shell 脚本时我们经常会用到/dev/null 设备,将 stdout、stderr 输出给它,也就是我们不想 要这些输出的数据。
通过重定向到/dev/null 忽略输出,比如我们没有安装 bc 计算器,正常会抛出没有发现命令:
 
这就让标准和错误输出到了空设备。
忽略标准输出:
 
忽略错误输出:
 
 

8.7 read 命令

read 命令从标准输入读取,并把输入的内容复制给变量。
命令格式: read [-ers] [-a array] [-d delim] [-i text] [-n nchars] [-N nchars] [-p prompt] [-t timeout] [-u fd] [name ...]
-e    在一个交互 shell 中使用 readline 获取行
-r    不允许反斜杠转义任何字符
-s    隐藏输入
-a array    保存为数组,元素以空格分隔
-d delimiter    持续读取直到遇到 delimiter 第一个字符退出
-n nchars    读取 nchars 个字符返回,而不是等到换行符
-p prompt    提示信息
-t timeout    等待超时时间,秒
-u fd    指定文件描述符号码作为输入,默认是 0
name    变量名
示例:
 
 
 


第九章    Shell 信号发送与捕捉

9.1    Linux 信号类型

信号(Signal):信号是在软件层次上对中断机制的一种模拟,通过给一个进程发送信号,执行相 应的处理函数。
进程可以通过三种方式来响应一个信号: 1)忽略信号,即对信号不做任何处理,其中有两个信号不能忽略:SIGKILL 及 SIGSTOP。
2)捕捉信号。
3)执行缺省操作,Linux 对每种信号都规定了默认操作。
Linux 究竟采用上述三种方式的哪一个来响应信号呢?取决于传递给响应的 API 函数。 Linux 支持的信号有:
编号    信号名称    缺省动作    描述
1    SIGHUP    终止    终止进程,挂起
2    SIGINT    终止    键盘输入中断命令,一般是 CTRL+C
3    SIGQUIT    CoreDump    键盘输入退出命令,一般是 CTRL+\
4    SIGILL    CoreDump    非法指令
5    SIGTRAP    CoreDump    trap 指令发出,一般调试用
 
6    SIGABRT    CoreDump    abort(3)发出的终止信号
7    SIGBUS    CoreDump    非法地址
8    SIGFPE    CoreDump    浮点数异常
9    SIGKILL    终止    立即停止进程,不能捕获,不能忽略

10    
SIGUSR1    
终止    用户自定义信号 1,像 Nginx 就支持 USR1 信号,用于重载配 置,重新打开日志
11    SIGSEGV    CoreDump    无效内存引用
12    SIGUSR2    终止    用户自定义信号 2
13    SIGPIPE    终止    管道不能访问
14    SIGALRM    终止    时钟信号,alrm(2)发出的终止信号

15    
SIGTERM    
终止    终止信号,进程会先关闭正在运行的任务或打开的文件再终 止,有时候有的进程在运行任务会忽略此信号。不能捕捉
16    SIGSTKFLT    终止    处理器栈错误
17    SIGCHLD    可忽略    子进程结束时,父进程收到的信号
18    SIGCONT    可忽略    让终止的进程继续执行
19    SIGSTOP    停止    停止进程,不能忽略,不能捕获
20    SIGSTP    停止    停止进程,一般是 CTRL+Z
21    SIGTTIN    停止    后台进程从终端读数据
22    SIGTTOU    停止    后台进程从终端写数据
23    SIGURG    可忽略    紧急数组是否到达 socket
24    SIGXCPU    CoreDump    超出 CPU 占用资源限制
25    SIGXFSZ    CoreDump    超出文件大小资源限制

26    
SIGVTALRM    
终止    虚拟时钟信号,类似于 SIGALRM,但计算的是进程占用的时 间
27    SIGPROF    终止    类似与 SIGALRM,但计算的是进程占用 CPU 的时间
28    SIGWINCH    可忽略    窗口大小改变发出的信号
 
29    SIGIO    终止    文件描述符准备就绪,可以输入/输出操作了
30    SIGPWR    终止    电源失败
31    SIGSYS    CoreDump    非法系统调用

CoreDump(核心转储):当程序运行过程中异常退出时,内核把当前程序在内存状况存储在一个 core 文件中,以便调试。执行命令 ulimit -c 如果是 0 则没有开启,也不会生成 core dump 文件, 可通过 ulimit -c unlimited 命令临时开启 core dump 功能,只对当前终端环境有效,如果想永久 生效,可修改/etc/security/limites.conf 文件,添加一行 "* soft core unlimited" 默认生成的 core 文件保存在可执行文件所在的目录下,文件名为 core。如果想修改 core 文件保存 路径,可通过修改内核参数:echo "/tmp/corefile-%e-%p-%t" > /proc/sys/kernel/core_pattern 则文件名格式为 core-命名名-pid-时间戳

Linux 支持两种信号:
一种是标准信号,编号 1-31,称为非可靠信号(非实时),不支持队列,信号可能会丢失,比如发 送多次相同的信号,进程只能收到一次,如果第一个信号没有处理完,第二个信号将会丢弃。 另一种是扩展信号,编号 32-64,称为可靠信号(实时),支持队列,发多少次进程就可以收到多 少次。 信号类型比较多,我们只要了解下,记住几个常用信号就行了,红色标记的我觉得需要记下。

发送信号一般有两种情况:
一种是内核检测到系统事件,比如键盘输入 CTRL+C 会发送 SIGINT 信号。 另一种是通过系统调用 kill 命令来向一个进程发送信号。

9.2    kill 命令

kill 命令发送信号给进程。
命令格式:kill [-s sigspec | -n signum | -sigspec] pid | jobspec ... kill -l [sigspec]
-s    # 信号名称
-n    # 信号编号
-l    # 打印编号 1-31 信号名称 示例:
 

9.3    trap 命令

trap 命令定义 shell 脚本在运行时根据接收的信号做相应的处理。
 
命令格式:trap [-lp] [[arg] signal_spec ...]
-l    # 打印编号 1-64 编号信号名称
arg    # 捕获信号后执行的命令或者函数 signal_spec # 信号名或编号 一般捕捉信号后,做以下几个动作: 1)清除临时文件
2)忽略该信号
3)询问用户是否终止脚本执行 示例 1:按 CTRL+C 不退出循环
 
示例 2:循环打印数字,按 CTRL+C 退出,并打印退出提示
 
示例 3:让用户选择是否终止循环
 
 
 


第十章    Shell 编程时常用的系统文件

10.1 Linux 系统目录结构

/    根目录,所有文件的第一级目录
/home    普通用户家目录
/root    超级用户家目录
/usr    用户命令、应用程序等目录
/var    应用数据、日志等目录
/lib    库文件和内核模块目录
/etc    系统和软件配置文件
/bin    可执行程序目录
/boot    内核加载所需的文件,grub 引导
/dev    设备文件目录,比如磁盘驱动
 
/tmp    临时文件目录
/opt    第三方软件安装目录

10.2 环境变量文件

系统级 系统级变量文件对所有用户生效。
/etc/profile    # 系统范围内的环境变量和启动文件。不建议把要做的事情写在这里面,最好创建 一个自定义的,放在/etc/profile.d 下
/etc/bashrc    # 系统范围内的函数和别名 用户级 用户级变量文件对自己生效,都在自己家目录下。
~/.bashrc    # 用户指定别名和函数
~/.bash_logout    # 用户退出执行
~/.bash_profile    # 用户指定变量和启动程序
~/.bash_history    # 用户执行命令历史文件
开启启动脚本顺序:/etc/profile -> /etc/profile.d/*.sh -> ~/.bash_profile -> ~/.bashrc ->
/etc/bashrc 因此,我们可以把写的脚本放到以上文件里执行。

10.3 系统配置文件

/etc/issue    系统版本
/etc/hosts    主机名与 IP 对应关系
/etc/resolv.conf    DNS 服务器地址
/etc/hostname    主机名
/etc/sysctl.conf    系统参数配置文件
/etc/sudoers    sudo 权限配置
/etc/init.d    服务启动脚本
/etc/sysconfig/network- scripts    
网卡信息配置目录

/etc/rc.d/rc.local    系统 init 初始化完后执行,不建议将启动服务写在这里面,应创建 自己的 systemd 或 udev
/etc/fstab    硬盘自动挂载配置
/etc/inittab    系统启动运行级别
 
/etc/crontab    系统级任务计划
/var/spool/cron    用户级任务计划,此目录下以用户名命名对应每个用户的任务计划
/etc/cron.d    描述计算机任务计划
/etc/hosts.allow    TCP 包访问列表
/etc/hosts.deny    TCP 包拒绝列表
/usr/share/doc    各软件的文档
/etc/sshd_config    SSH 服务配置文件
/var/log    系统和应用程序日志目录
/var/spool/mail    邮件目录
crontab 任务计划说明:
 

10.4    /dev 目录

/dev 目录下存放的是一些设备文件。
/dev/hd[a-t]    IDE 设备
/dev/sd[a-z]    SCSI 设备
/dev/dm-[-9]    LVM 逻辑磁盘
/dev/null    黑洞
/dev/zero    无限 0 数据流

10.5    /proc 目录

/proc 是一个虚拟目录,在 Linux 系统启动后生成的,数据存储在内存中,存放内核运行时的参数、 网络信息、进程状态等等。
 
10.5.1    /proc


/proc/[0-9]+    此目录下数字命名的目录是运行进程信息,目录名为 PID
/proc/meminfo    物理内存、交换空间等信息,free
/proc/loadavg    系统负载


/proc/uptime    系统运行时间 计算系统启动时间:
date    -d    "$(awk    -F.    \'{print    $1}\'    /proc/uptime)    second    ago"
+"%Y-%m-%d %H:%M:%S"
或    who -b
/proc/cpuinfo    CPU 信息
/proc/modules    系统已加载的模块或驱动,lsmod
/proc/mounts    文件系统挂载信息,mount
/proc/swaps    swap 分区信息
/proc/partitions    系统分区信息
/proc/version    内核版本
/proc/stat    CPU 利用率,磁盘,内存页
/proc/devices    可用的设备列表

10.5.2    /proc/net

/proc/net 目录存放的是一些网络协议信息。
/proc/net/tcp    TCP 状态连接信息,netstat
/proc/net/udp    UDP 状态连接信息
/proc/net/arp    arp 信息表
/proc/net/dev    网卡流量
/proc/net/snmp    网络传输协议的收发包信息
/proc/net/sockstat    socket 使用情况,比如已使用,正在使用
/proc/net/netstat    网络统计数据,netstat -s
 
/proc/net/route    路由表

10.5.3    /proc/sys

这个目录下的文件可被读写,存了大多数内核参数,可以修改改变内核行为。所以修改这些文件要特 别小心,修改错误可能导致内核不稳定。
有四个主要的目录:
fs    # 文件系统各方面信息,包括配额、文件句柄、inode 和目录项。 kernel    # 内核行为的信息
net    # 网络配置信息,包括以太网、ipx、ipv4 和 ipv6。 vm    # Linux 内核的虚拟内存子系统,通常称为交换空间。

/proc/sys/fs/file-max    内核分配所有进程最大打开文件句柄数量,可 适当增加此值

/proc/sys/fs/file-nr    只读,第一个值已分配的文件句柄数量,第二 个值分配没有使用文件句柄数量,第三个值文 件句柄最大数量。lsof

/proc/sys/kernel/ctrl-alt-del    组合键重启计算机,只为 0 同步缓冲区到磁盘,
1 为不同步
/proc/sys/kernel/domainname    配置系统域名

/proc/sys/kernel/exec-shield    配置内核执行保护功能,防止某类型缓冲区溢 出攻击。0 为禁用,1 开启
/proc/sys/kernel/hostname    配置系统主机名
/proc/sys/kernel/osrelease    内核版本号
/proc/sys/kernel/ostype    操作系统类型
/proc/sys/kernel/shmall    设置共享内存的总量,以字节为单位
/proc/sys/kernel/shmmax    设置最大共享内存段
/proc/sys/kernel/shmmni    设置共享内存段最大数量
/proc/sys/kernel/threads-max    设置最大允许线程数量
/proc/sys/kernel/pid_max    设置最大允许创建的 pid 数量
/proc/sys/kernel/version    显示最后一次编译内核时间
/proc/sys/kernel/random/uuid    生成 uuid
 
/proc/sys/kernel/core_pattern    控制生成 core dump 文件位置和保存格式
/proc/sys/net/core/netdev_max_backlog    设置数据包队列允许最大数量
/proc/sys/net/core/optmem_max    设置 socket 允许最大缓冲区大小
/proc/sys/net/core/somaxconn    每个端口最大监听队列长度
/proc/sys/net/core/rmem_default    设置 socket 接收默认缓冲区大小,单位字节
/proc/sys/net/core/rmem_max    设置 socket 接收最大缓冲区大小
/proc/sys/net/core/wmem_default    设置 socket 发送默认缓冲区大小
/proc/sys/net/core/wmem_max    设置 socket 发送最大缓冲区大小
/proc/sys/net/ipv4/icmp_echo_ignore_all 和 icmp_echo_ignore_broadcasts    设置是否忽略 icmp 响应包和广播包,0 为不忽 略,1 为忽略
/proc/sys/net/ipv4/ip_default_ttl    设置默认生存时间

/proc/sys/net/ipv4/ip_forward    允许系统接口转发数据包,默认 0 为关闭,1 为 开启

/proc/sys/net/ipv4/ip_local_port_range    指定使用本地 TCP 或 UDP 端口范围,第一个值 最低,第二个值最高
/proc/sys/net/ipv4/tcp_syn_retries    限制重新发送 syn 尝试建立连接次数
/proc/sys/net/ipv4/tcp_synack_retries    syn ack 确认包尝试次数

/proc/sys/net/ipv4/tcp_syncookies    是否启用 syn cookie,0 为关闭,默认 1 为开 启
/proc/sys/net/ipv4/tcp_max_tw_buckets    系统保持 TIME_WAIT 最大数量

/proc/sys/net/ipv4/tcp_tw_recycle    是否启用 TIME_WAIT 快速收回,默认 0 为关闭, 1 为开启

/proc/sys/net/ipv4/tcp_tw_reuse    是否启用 TIME_WAIT 复用,默认 0 为关闭,1 为开启

/proc/sys/net/ipv4/tcp_keepalive_time    TCP 连接保持时间(默认 2 小时),当连接活动, 定时器会重新复位。

/proc/sys/vm/swappiness    内核按此值百分比来使用 swap,值越小越不考 虑使用物理内存,0 为尽可能不使用 swap
 


/proc/sys/vm/overcommit_memory    控制内存分配,默认 0 为内核先评估可用内存, 如果足够允许申请,否则拒绝,1 为允许分配 所有物理内存,2 为允许分配超过物理内存和 交换空间总和的内存

/proc/sys/vm/overcommit_ratio    指定物理内存比率,当 overcommit_memory=2 时,用户空间进程可使用的内存不超过物理内 存*overcommit_ratio+swap

参考资料: https://access.redhat.com/documentation/en-
US/Red_Hat_Enterprise_Linux/6/html/Deployment_Guide/s2-proc-dir-sys.html


第十一章    Shell 常用命令与工具

本章节学习一些在编写 Shell 时的常用命令或工具及使用技巧。有人说 Shell 脚本是命令堆积的一 个文件,按顺序去执行。还有人说想学好 Shell 脚本,要把 Linux 上各种常见的命令或工具掌握 了,这些说法都没错。由于 Shell 语言本身在语法结构上比较简单,是面向过程编程,想实现复杂 的功能有点强人所难!而且 Shell 本身又工作在 Linux 内核之上,在用户态调用 Linux 命令会很方 面,所以大多数情况下我们都是依靠这些命令来完成脚本中的某些功能,比如文本处理、获取系统 状态等等,然后通过 Shell 语法结构组织代码逻辑。不管是学 Linux 系统好还是写 Shell 脚本也 好,有些命令都是必须要会的,以下是根据个人经验总结的一些常用的命令。 怎么更好的学习命令呢?
当然查看官方帮助文档了,可以通过 man cmd、cmd --help、help cmd、info cmd 等方式查看命令的 使用。

11.1    ls

功能:列出目录内容 常用选项:
-a    显示所有文件,包括隐藏的
-l    长格式列出信息
-i    显示文件 inode 号
-t    按修改时间排序
-r    按修改时间倒序排序
-h    打印易读大小单位 示例:
 
 
11.2    echo

功能:打印一行 常用选项:
-n    不加换行符
-e    解释转义符 示例: 解释换行符:
 

11.3    printf

功能:格式化打印数据。默认打印字符串不换行。 格式:printf format [arguments]
Format    描述
%s    一个字符串
%d,%i    一个小数
%f    一个浮点数
%.ns    输出字符串,n 是输出几个字符
%m.nf    输出浮点数,m 是输出整数位数,n 是输出的小数位数
%x    不带正负号的十六进制,使用 a 至 f 表示 10 到 15
%X    不带正负号的十六进制,使用 A 至 F 表示 10 至 15
%%    输出单个%
%-5s    左对齐,对参数每个字段左对齐,宽度为 5
%-4.2f    左对齐,宽度为 4,保留两位小数
%5s    右对齐,不加横线表示右对齐

一些常用的空白符:
\n    换行
\r    回车
\t    水平制表符 示例:
 
 

11.4    cat

功能:连接文件和标准输出打印 常用选项:
-b    显示非空行行号
-n    显示所有行行号
-T    显示 tab,用^I 表示
-E    显示以$结尾 示例:
 
 
 

11.5    tac

功能:连接文件和倒序打印文件 常用选项:
示例: 倒序打印每一行:
 

11.6    rev

功能:反向打印每一行 常用选项:
示例:
 

11.7    wc

功能:统计文件行数、字节、字符数 常用选项:
-c    打印文件字节数,一个英文字母 1 字节,一个汉字占 2-4 字节(根据编码)
-m    打印文件字符数,一个汉字占 2 个字符
-l    打印多少行
-L    打印最长行的长度,也可以统计字符串长度 示例:
 

11.8    cp

功能:复制文件或目录 常用选项:
-a    归档
-b    目标文件存在创建备份,备份文件是文件名跟~
-f    强制复制文件或目录
-r    递归复制目录
 
-p    保留原有文件或目录属性
-i    覆盖文件之前先询问用户
-u    当源文件比目的文件修改时间新时才复制
-v    显示复制信息 示例:
 

11.9    mkdir

功能:创建目录 常用选项:
-p    递归创建目录
-v    显示创建过程 示例:
 

11.10    mv

功能:移动文件或重命名 常用选项:
-b    目标文件存在创建备份,备份文件是"文件名后跟~"
-u    当源文件比目的文件修改时间新时才移动
-v    显示移动信息 示例:
 

11.11    rename

功能:重命名文件,支持通配符 常用选项: 示例:批量命名文件
 
 
 

11.12    dirname

功能:去除路径的最后一个名字 常用选项:
示例:
 

11.13    basename

功能:打印路径的最后一个名字 常用选项:
-a    支持多个参数
-s    删除后面的后缀 示例:
 

11.14    du

功能:估算文件磁盘空间使用 常用选项:
-h    易读格式显示(K,M,G)
-b    单位 bytes 显示
-k    单位 KB 显示
-m    单位 MB 显示
-s    只显示总大小
--max-depth=<目录层数>,超过层数的目录忽略
--exclude=file 排除文件或目录
--time    显示大小和创建时间
 
示例:
 

11.15    cut

功能:选取文件的每一行数据 常用选项:
-b    选中第几个字符
-c    选中多少个字符
-d    指定分隔符分字段,默认是空格
-f    显示选中字段 示例:
 

11.16    tr

功能:替换或删除字符
格式:Usage: tr [OPTION]... SET1 [SET2]
常用选项:
-c    替换 SET1 没有 SET2 的字符
-d    删除 SET1 中字符
-s    压缩 SET1 中重复的字符
-t    将 SET1 用 SET2 转换,默认 示例:
 
 
 

11.17    stat

功能:显示文件或文件的系统状态 常用选项:
-Z    显示 selinux 安全上下文
-f    显示文件系统状态
-c    指定格式输出内容
-t    以简洁的形式打印 示例:
 

11.18    seq

功能:打印序列化数字 常用选项:
-f    使用 printf 样式格式
-s    指定换行符,默认是\n
-w    等宽,用 0 填充 示例:
 
 
 

11.19    shuf

功能:生成随机序列 常用选项:
-i    输出数字范围
-o    结果写入文件 示例: 输出范围随机数:
 

11.20    sort

功能:排序文本,默认对整列有效 常用选项:
-f    忽略字母大小写
-M    根据月份比较,比如 JAN、DEC
-h    根据易读的单位大小比较,比如 2K、1G
-g    按照常规数值排序
-n    根据字符串数值比较
-r    倒序排序
-k    位置 1,位置 2    根据关键字排序,在从第位置 1 开始,位置 2 结束
 
-t    指定分隔符
-u    去重重复行
-o    将结果写入文件 示例:
 

11.21    uniq

功能:去除重复行,只会统计相邻的 常用选项:
-c    打印出现的次数
-d    只打印重复行
-u    只打印不重复行
-D    只打印重复行,并且把所有重复行打印出来
-f N 比较时跳过前 N 列
-i    忽略大小写
-s N 比较时跳过前 N 个字符
-w N 对每行第 N 个字符以后内容不做比较
 
示例:

测试文本如下:
# cat file abc
cde xyz cde xyz abd
去重复行:
# sort file |uniq abc
abd cde xyz
打印每行重复次数:
# sort file |uniq -c
1 abc
1    abd
2    cde
2 xyz 打印不重复行:
# sort file |uniq -u
abc abd
打印重复行:
# sort file |uniq -d cde
xyz 打印重复行并统计出现次数:
# sort file |uniq -d -c 2 cde
2 xyz
根据前几个字符去重:
# sort file |uniq -w 2 abc
cde
xyz


11.22    tee

功能:从标准输入读取写到标准输出和文件 常用选项:
-a    追加到文件 示例:
 
 
 

11.23    join

功能:连接两个文件 常用选项:
-i    忽略大小写
-o    按照指定文件栏位显示
-t    使用字符作为输入和输出字段分隔符 示例:
 

11.24    paste

功能:合并文件 常用选项:
-d    指定分隔符,默认是 tab 键分隔
-s    将文件内容平行合并,默认 tab 键分隔 示例:
 
 
 

11.25    head

功能:输出文件的前几行 常用选项:
-c    打印前多少 K,M
-n    打印前多少行 示例:
 

11.26    tail

功能:输出文件的后几行 常用选项:
-c    打印后多少 K,M
-f    实时读文件,随着文件输出附加输出
-n    输出最后几行
--pid    与-f 一起使用,表示 pid 死掉后结束
-s    与-f 一起使用,表示休眠多少秒输出 示例:
 

11.27    find

功能:目录层次结构中搜索文件 格式:find path -option actions 常用选项:
-name    文件名,支持(‘*’, ‘?’)
-type    文件类型,d 目录,f 常规文件等
-perm    符合权限的文件,比如 755
 
-atime -/+n    在 n 天以内/过去 n 天被访问过
-ctime -/+n    在 n 天以内/过去 n 天被修改过
-amin -/+n    在 n 天以内/过去 n 分钟被访问过
-cmin -/+n    在 n 天以内/过去 n 分钟被修改过
-size -/+n    文件大小小于/大于,b、k、M、G
-maxdepth levels    目录层次显示的最大深度
-regex pattern    文件名匹配正则表达式模式
-inum    通过 inode 编号查找文件 动作:
-detele    删除文件
-exec command {} \;    执行命令,花括号代表当前文件
-ls    列出当前文件,ls -dils 格式
-print    完整的文件名并添加一个回车换行符
-print0    打印完整的文件名并不添加一个回车换行符
-printf format    打印格式 其他字符:
! 取反
-or/-o    逻辑或
-and    逻辑和 示例:
 
 
 

11.28    xargs

功能:从标准输入执行命令 常用选项:
-a file    从指定文件读取数据作为标准输入
-0    处理包含空格的文件名,print0
-d    delimiter    分隔符,默认是空格分隔显示
-i    标准输入的结果以{}代替
-I    标准输入的结果以指定的名字代替
-t    显示执行命令
-p    交互式提示是否执行命令
-n    最大命令行参数
--show-limits    查看系统命令行长度限制 示例:
 

11.29    nl

功能:打印文件行号 常用选项:
-b <a|t>    指定行号显示方式,a 表示所有行都打印行号,b 表示空行不显示行号,默认是 a
-n <ln|rn|rz>    行号显示方法,ln 左对齐,rn 右对齐,rz 右边显示,左边空白用 0 填充。
-w    行号栏位在左边占用的宽度 示例:
 
 
 

11.30    date

功能:打印或设置系统日期和时间 常用选项:
-d string    显示指定字符串所描述的时间,而非当前时间
-f datefile 从日期文件中按行读入时间描述
-I    输出 ISO 8601 格式的日期和时间
-r    显示文件的最后修改时间
-R    输出 RFC 2822 格式的日期和时间
-s string    设置时间所描述的字符串
-u    打印或设置 UTC 时间 控制输出格式:
%%    一个文字的 %
%a    当前 locale 的星期名缩写(例如: 日,代表星期日)
%A    当前 locale 的星期名全称 (如:星期日)
%b    当前 locale 的月名缩写 (如:一,代表一月)
%B    当前 locale 的月名全称 (如:一月)
%c    当前 locale 的日期和时间 (如:2005 年 3 月 3 日 星期四 23:05:25)
%C    世纪;比如 %Y,通常为省略当前年份的后两位数字(例如:20)
%d    按月计的日期(例如:01)
%D    按月计的日期;等于%m/%d/%y
%e    按月计的日期,添加空格,等于%_d
%F    完整日期格式,等价于 %Y-%m-%d
%g    ISO-8601 格式年份的最后两位 (参见%G)
%G    ISO-8601 格式年份 (参见%V),一般只和 %V 结合使用
%h    等于%b
%H    小时(00-23)
%I    小时(00-12)
%j    按年计的日期(001-366)
%k    时(0-23)
%l    时(1-12)
%m    月份(01-12)
%M    分(00-59)
%n    换行
%N    纳秒(000000000-999999999)
%p    当前 locale 下的"上午"或者"下午",未知时输出为空
%P    与%p 类似,但是输出小写字母
%r    当前 locale 下的 12 小时时钟时间 (如:11:11:04 下午)
%R    24 小时时间的时和分,等价于 %H:%M
%s    自 UTC 时间 1970-01-01 00:00:00 以来所经过的秒数
%S    秒(00-60)
%t    输出制表符 Tab
 
%T    时间,等于%H:%M:%S
%u    星期,1 代表星期一
%U    一年中的第几周,以周日为每星期第一天(00-53)
%V    ISO-8601 格式规范下的一年中第几周,以周一为每星期第一天(01-53)
%w    一星期中的第几日(0-6),0 代表周一
%W    一年中的第几周,以周一为每星期第一天(00-53)
%x    当前 locale 下的日期描述 (如:12/31/99)
%X    当前 locale 下的时间描述 (如:23:13:48)
%y    年份最后两位数位 (00-99)
%Y    年份 示例:
 

11.31    wget

功能:非交互式网络下载,类似于 HTTP 客户端 常用选项:
-b,    --background    后台运行 日志记录和输入文件:
-o,    --output-file=FILE    日志写到文件
-a,    --append-output=FILE    日志追加到文件
-d,    --debug    打印 debug 信息,会包含头信息
-q,    --quiet    退出,不输出
 
-i,    --input-file=FILE    从文件中读取 URL 下载 下载选项:
-t,    --tries=NUMBER    设置链接重试次数
-O,    --output-document=FILE    写入内容到文件
-nc, --no-clobber    跳过下载现有的文件
-c,    --continue    断点续传
--progress=TYPE    设置进度条(dot 和 bar)
-S,    --server-response    打印服务器响应头信息
--spider    不下载任何内容
-T,    --timeout=SECONDS    设置相应超时时间(还有--dns-timeout、--connect-timeout 和
--read-timeout)
-w,    --wait=SECONDS    两次重试间隔等待时间
--bind-address=ADDRESS    设置绑定地址
--limit-rate=RATE    限制下载速度
--user=USER    设置 ftp 和 http 用户名
--password=PASS    设置 ftp 和 http 密码 目录:
-P,    --directory-prefix=PREFIX    保存文件目录 HTTP 选项:
--http-user=USER    设置 http 用户名
--http-password=PASS    设置 http 密码
--proxy-user=USER    设置代理用户名
--proxy-password=PASS    设置代理密码
--referer=URL    设置 Referer
--save-headers    保存头到文件
--default-page=NAME    改变默认页面名字,默认 index.html
-U,--user-agent=AGENT    设置客户端信息
--no-http-keep-alive    禁用 HTTP keep-alive(长连接)
--load-cookies=FILE    从文件加载 cookies
--save-cookies=FILE    保存 cookies 到文件
--post-data=STRING    使用 POST 方法,发送数据 FTP 选项:
--ftp-user=USER    设置 ftp 用户名
--ftp-password=PASS    设置 ftp 密码
--no-passive-ftp    禁用被动传输模式 递归下载:
-r, --recursive    指定递归下载
-l, --level=NUMBER    最大递归深度
-A, --accept=LIST    逗号分隔下载的扩展列表
-R, --reject=LIST    逗号分隔不被下载的扩展列表
-D, --domains=LIST    逗号分隔被下载域的列表
--exclude-domains=LIST    排除不被下载域的列表 示例:
 
 

# wget -t 3 -c http://nginx.org/download/nginx-1.11.7.tar.gz -P down 不下载任何内容,判断 URL 是否可以访问:
# wget --spider http://nginx.org/download/nginx-1.11.7.tar.gz 下载内容写到文件:
# wget http://www.baidu.com/index.html -O index.html 从文件中读取 URL 下载:
# wget -i url.list 下载 ftp 文件:
# wget --ftp-user=admin --ftp-password=admin ftp://192.168.1.10/ISO/CentOS-6.5-i386- minimal.iso
伪装客户端,指定 user-agent 和 referer 下载:
# wget -U "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.157 Safari/537.36" --referer "http://nginx.org/en/download.html" http://nginx.org/download/nginx-1.11.7.tar.gz
查看 HTTP 头信息:
# wget -S http://nginx.org/download/nginx-1.11.7.tar.gz
# wget --debug http://nginx.org/download/nginx-1.11.7.tar.gz


11.32    curl

功能:发送数据到 URL,类似于 HTTP 客户端 常用选项:
-k, --insecure    允许 HTTPS 连接网站
-C, --continue-at    断点续传
-b, --cookie STRING/FILE    从文件中读取 cookie
-c, --cookie-jar    把 cookie 保存到文件
-d, --data    使用 POST 方式发送数据
--data-urlencode    POST 的数据 URL 编码
-F, --form    指定 POST 数据的表单
-D, --dump-header    保存头信息到文件
--ftp-pasv    指定 FTP 连接模式 PASV/EPSV
-P, --ftp-port    指定 FTP 端口
-L, --location    遵循 URL 重定向,默认不处理
-l, --list-only    指列出 FTP 目录名
-H, --header    自定义头信息发送给服务器
-I, --head    查看 HTTP 头信息
-o, --output FILE    输出到文件
-#, --progress-bar    显示 bar 进度条
-x, --proxy [PROTOCOL://]HOST[:PORT]    使用代理
-U, --proxy-user USER[:PASSWORD] 代理用户名和密码
-e, --referer    指定引用地址 referer
-O, --remote-name    使用远程服务器上名字写到本地
--connect-timeout    连接超时时间,单位秒
--retry NUM    连接重试次数
--retry-delay    两次重试间隔等待时间
-s, --silent    静默模式,不输出任何内容
-Y, --speed-limit    限制下载速率
 
-u, --user USER[:PASSWORD] 指定 http 和 ftp 用户名和密码
-T, --upload-file    上传文件
-A, --user-agent    指定客户端信息 示例:
 

11.33    scp

功能:基于 SSH 的安全远程服务器文件拷贝 常用选项:
-i    指定私钥文件
-l    限制速率,单位 Kb/s,1024Kb=1Mb
-P    指定远程主机 SSH 端口
-p    保存修改时间、访问时间和权限
-r    递归拷贝目录
-o    SSH 选项,有以下几个比较常用的: ConnectionAttempts=NUM    连接失败后重试次数 ConnectTimeout=SEC    连接超时时间 StrictHostKeyChecking=no    自动拉去主机 key 文件 PasswordAuthentication=no   禁止密码认证 示例:
 
 
 

11.34    rsync

功能:远程或本地文件同步工具 常用选项:
-v    显示复制信息
-q    不输出错误信息
-c    跳过基础效验,不判断修改时间和大小
-a    归档模式,等效-rlptgoD,保留权限、属组等
-r    递归目录
-l    拷贝软连接
-z    压缩传输数据
-e    指定远程 shell,比如 ssh、rsh
--progress    进度条,等同-P
--bwlimit=KB/s    限制速率,0 为没有限制
--delete    删除那些 DST 中 SRC 没有的文件
--exclude=PATTERN    排除匹配的文件或目录
--exclude-from=FILE    从文件中读取要排除的文件或目录
--password-file=FILE    从文件读取远程主机密码
--port=PORT    监听端口 示例:
 

11.35    nohup

功能:运行程序,忽略挂起信号 示例:
 
 
11.36    iconv

功能:将文件内容字符集转成其他字符集 常用选项:
-l    列出所有已知的字符集
-f    原始文本编码
-t    输出编码
-o    输出到文件
-s    关闭警告 示例:
 

11.37    uname

功能:输出系统信息 常用选项:
-a    输出以下所有信息
-s    输出内核名称
-n    输出主机名
-r    输出内核发行版
-v    输出内核版本
-m    输出主机的硬件架构名称
-p    输出处理器类型或"unknown"
-i    输出硬件平台或"unknown
-o    输出操作系统名称 示例:
 

11.38    sshpass

功能:非交互 SSH 登录(需要安装) 常用选项:
 
-f    从文件中获取密码
-d    用文件描述符数字获取密码
-p    指定 SSH 密码
-e    密码作为环境变量传递,变量名是 SSHPASS 示例:
 

11.39    tar

功能:归档目录或文件 常用选项:
-c    创建新归档
-d    比较归档和文件系统的差异
-r    追加文件到归档
-t    存档的内容列表
-x    提取归档所有文件
-C    改变解压目录
-f    使用归档文件或设备归档
-j    bzip2 压缩
-z    gzip 压缩
-v    输出处理过程 示例:
 

11.40    logger

功能:系统日志的 shell 命令行接口 常用选项:
 
-i    每行记录进程 ID
-f    指定输出日志到文件
-p    设置记录的优先级
-t    添加标签 示例:
 

11.41    netstat

功能:打印网络连接、路由表、接口统计信息、伪装连接和多播成员 常用选项:
-r    显示路由表
-i    显示接口表
-n    不解析名字
-p    显示程序名 PID/Program
-l    显示监听的 socket
-a    显示所有 socket
-o    显示计时器
-Z    显示上下文
-t    只显示 tcp 连接
-u    只显示 udp 连接
-s    显示每个协议统计信息 示例:
 

11.42    ss

功能:比 netstat 更强大的 socket 查看工具 格式:ss [options] [ FILTER ] 常用选项:
-n    不解析名字
-a    显示所有 socket
-l    显示所有监听的 socket
-o    显示计时器
-e    显示 socket 详细信息
-m    显示 socket 内存使用
-p    显示进程使用的 socket
-i    显示内部 TCP 信息
-s    显示 socket 使用汇总
 
-4    只显示 IPV4 的 socket
-0    显示包 socket
-t    只显示 TCP socket
-u    只显示 UDP socket
-d    只显示 DCCP socket
-w    只显示 RAW socket
-x    只显示 Unix 域 socket
-f    FAMILY    只显示 socket 族类型(    unix, inet, inet6, link, netlink)
-A    查询 socket {all|inet|tcp|udp|raw|unix|packet|netlink}[,QUERY]
-D    将原始的 TCP socket 转储到文件
-F    从文件中读取过滤信息 过滤:
-o    state    显示 TCP 连接状态信息
示例:
 

11.43    lsof

功能:列出打开的文件 常用选项:
-i [i]    监听的网络地址,如果没有指定,默认列出所有。
[i]来自[46][protocol][@hostname|hostaddr][:service|port]
-U    列出 Unix 域 socket 文件
-p    指定 PID
-u    指定用户名或 UID 所有打开的文件
+D    递归搜索 示例:
 
 
 

11.44    ps

功能:报告当前进程的快照 常用选项:
-a    显示所有进程
-u    选择有效的用户 ID 或名称
-x    显示无控制终端的进程
-e    显示所有进程
-f    全格式
-r    只显示运行的进程
-T    这个终端的所有进程
-p    指定进程 ID
--sort    对某列排序
-m    线程
-L    格式化代码列表
-o    用户自定义格式
CODE    NORMAL    HEADER
%C    pcpu    %CPU
%G    group    GROUP
%P    ppid    PPID
%U    user    USER
%a    args    COMMAND
%c    comm    COMMAND
%g    rgroup    RGROUP
%n    nice    NI
%p    pid    PID
%r    pgid    PGID
%t    etime    ELAPSED
%u    ruser    RUSER
%x    time    TIME
%y    tty    TTY
 
%z    vsz    VSZ 示例:
 
USER    PID %CPU %MEM    VSZ    RSS TTY    STAT START    TIME COMMAND
USER 进程所有者 PID 进程 ID
%CPU 占用 CPU 时间
%MEM 物理内存
VSZ  虚拟内存大小(kb) RSS 驻留集内存页数量(kb) TTY 终端
STAT 进程状态;R 运行,S 休眠,D 不可中断,T 停止,Z 僵尸,N 表示普通优先级更低的优先级 START 进程启动时间
TIME 使用 CPU 总时间 COMMAND 命令名称和参数

11.45    top

功能:动态显示活动的进程和系统资源利用率 常用选项:
-d    信息刷新时间间隔
-p    只监控指定的进程 PID
-i    只显示正在使用 CPU 的进程
-H    显示线程
-u    只查看指定用户名的进程
-b    将输出编排成易处理格式,适合输出到文件处理
-n    指定最大循环刷新数 交互命令:
f    添加或删除显示的指标 c    显示完整命令
P    按 CPU 使用百分比排序
M    按驻留内存大小排序
T 按进程使用 CPU 时间排序 1 显示每个 CPU 核心使用率 k   终止一个进程
 
示例:
 

 

第一行:当前系统时间,系统运行了多长时间(9 天 22 小时 16 分钟),CPU 负载:1 分钟、5 分钟、 15 分钟
第二行:系统总共 178 个进程,3 个 CPU 正在处理,175 在休眠等待处理,0 个停止,0 个僵尸进程 第三行:us 用户空间使用 CPU 时间 0.3%,sy 内核空间使用 CPU 时间 0.3%,ni 系统调整进程优先级 使用 CPU 时间 0.0%,id 空闲 CPU 时间 99.3%,wa 等待 I/O 响应 CPU 时间 0.0%,hi 硬中断,si 软中 断。
第四行和第五行:物理内存与交换分区使用率 第六行:
PID 进程 ID
USER 进程所有者 PR 进程优先级
NI 负值表示高优先级,正值表示低优先级
VIRT 进程启动后使用虚拟内存总量(KB),VIRT=SWAP+RES RES 实际物理内存使用大小(KB),RES=CODE+DATA
SHR 共享内存大小(KB),可能与其他进程共享的内存;计算进程使用物理内存大小:RES-SHR S 进程状态;R 运行,S 休眠,D 不可中断,T 停止,Z 僵尸
%CPU 上次更新到现在的 CPU 时间占用百分比
%MEM 使用物理内存百分比 TIME+ 使用 CPU 总时间 COMMAND 命令名称和参数

11.46    free

功能:查看内存使用率 常用选项:
-b    bytes 显示
-k    KB 显示
-m    M 显示
-g    G 显示
-h    易读单位显示
-s    每几秒重复打印
-c    重复打印几次退出 示例:
 
 
 

11.47    df

功能:查看文件系统的磁盘空间使用情况 常用选项:
-a    包含虚拟文件系统
-h    可易读单位显示
-i    显示 inode 信息而非块使用量
-k    1K 块的数量
-t    只显示指定文件系统为指定类型的信息
-T    显示文件系统类型 示例:
 

11.48    vmstat

功能:报告虚拟内存、swap、io、上下文和 CPU 统计信息。 分析了这些文件:
/proc/meminfo
/proc/stat
/proc/*/stat 常用选项:
-a    打印活跃和不活跃的内存页
-d    打印硬盘统计信息
-D    打印硬盘表
-p    打印硬盘分区统计信息
-s    打印虚拟内存表
-m    打印内存分配(slab)信息
-t    添加时间戳到输出
-S    显示单位,默认 k、KB、m、M,大写是*1024 示例:
 
 
r:CPU 正在运行的进程数 b:在等待 I/O 的进程数 swpd:已经使用的交换内存(kb) free:空闲的物理内存(kb)
buff:已经使用的缓冲区内存(kb);一般对设备数据缓存,写入到磁盘的数据。
 
cache:已经使用的缓冲区内存(kb);一般对文件数据缓存,从磁盘读取的数据。 si:从磁盘交换到内存的交换页数量(kb/s) so:从内存交换到磁盘的交换页数据(kb/s)   bi:块设备接收的块数量(kb/s)
bo:块设备发送的块数量(kb/s) in:每秒 CPU 中断次数
cs:每秒 CPU 上下文切换次数 us:用户进程使用 CPU 时间(%) sy:系统进程使用 CPU 时间(%) id:CPU 空闲时间(%)
wa:等待 I/O 响应所消耗的 CPU 时间(%) st:从虚拟设备中获得的时间(%11.49    iostat

功能:报告 CPU 利用率和磁盘 I/O
用法: iostat [ 选项 ] [ <时间间隔> [ <次数> ] ] 常用选项:
-c    显示 CPU 使用率
-d    只显示磁盘使用率
-k    单位 KB/s 代替 Block/s
-m    单位 MB/s 代替 Block/s
-N    显示所有映射设备名字
-t    打印报告时间
-x    显示扩展统计信息 示例:
 

11.50    sar

功能:查看系统资源综合方面利用率 常用选项:
-u, CPU
-r, memory
-b, disk
-n DEV, NIC traffic
-q, systemload
-b, TPS(Transaction Per Second,每秒事务处理量)
-o, output to file 示例:
 
 
11.51    dstat

功能:查看系统资源综合方面利用率(需要安装) 常用选项:
-c    cpu 统计
-d    磁盘统计
-m    内存统计
-n    网络统计
-s    swap 统计
-l    负载统计
--tcp    tcp 状态统计
--udp    udp 状态统计
--socket    socket 数量统计
-t    输出时间
--output    写入 csv 文件 插件:
--list    支持的插件
--top-bio-adv    详细显示 I/O 进程写入 block 量,包括 pid、r、w 和 cpu
--top-io-adv    进程写入磁盘总量
--top-cpu    占用 CPU 进程
--top-cpu-adv    查看最高 CPU 进程
--top-mem    内存进程 示例:
 

11.52    ip

功能:查看/操作路由表、设备、路由策略和隧道 格式:ip [ OPTIONS ] OBJECT { COMMAND | help }
常用选项:
-b, -batch <FILENAME>  从文件或标准输入读取命令并调用他们,第一次失败将终止
-force    批量模式有错误不终止,如果有错误则状态返回非 0
-s, -statistics      输出更多的统计信息
-l, -loops <COUNT>    指定最大的循环数 操作对象(OBEJECT):
address    网络设备地址 12tp    以太网 IP 隧道
link    配置网络设备 maddress    多播地址
monitor    动态监控网络连接 mroute    多播路由缓存条目
mrule 角色在多播路由策略数据库 neighbour 管理 ARP 或 NDISC 缓存条目 netns     管理网络命名空间
 
ntable    管理 neighbour 缓存操作 route    路由表
rule    角色在路由策略数据库 tpc_metrics/tcpmetrics 管理 TCP 指标 tunnel    IP 隧道
tuntap    管理 TUN/TAP 设备 xfrm    管理 IPSec 策略
可通过 ip OBEJECT help 再查看对象的操作方法。 示例:
 

11.53    nc

功能:TCP 和 UDP 连接和监听 常用选项:
-i interval 指定间隔时间发送和接受行文本
-l    监听模式,管理传入的连接
-n    不解析域名
-p    指定本地源端口
-s    指定本地源 IP 地址
-u    使用 udp 协议,默认是 tcp
-v    执行过程输出
-w    timeout 连接超时时间
 
-x    proxy_address[:port]    请求连接主机使用代理地址和端口
-z    指定扫描监听端口,不发送任何数据 示例:
 

11.54    time

功能:执行脚本时间 常用选项:   示例:
 
 
11.55    eval

功能:执行参数作为 shell 命令 示例:
 

11.56    ssh

功能:SSH 客户端 常用选项:
-p    指定远程主机端口
-i    指定认证文件
-L    [bind_address:]port:host:hostport
-R    [bind_address:]port:host:hostport]
-D    [bind_address:]port
-o    SSH 选项,有以下几个比较常用的: ConnectionAttempts=NUM    连接失败后重试次数 ConnectTimeout=SEC    连接超时时间 StrictHostKeyChecking=no    自动拉去主机 key 文件 PasswordAuthentication=no   禁止密码认证 示例:
 
SSH 还提供了一个非常有用的功能,就是端口转发,能帮你解决一些无法建立的连接。
1)本地端口转发
应用场景 1:A 不能访问 C,B 能访问 A 和 C,实现通过 B 能让 A 访问 C 在主机 A 执行:
# ssh -L 2222:主机 C:22 主机 B # ssh -L [绑定地址:]本地端口:主机 C:C 端口 主机 B
将 SSH 绑定本地端口 2222,本地 2222 端口数据转发主机 B,主机 B 的所有数据转发到主机 C 的 22 端 口;这样一来,只要在主机 A ssh -p 2222 localhost,就等于连上了主机 C 的 22 端口。 应用场景 2:一台 Squid 代理服务器,限制了本机可以清理缓存,但是我想从远程服务器清理 在远程服务器执行:
# ssh -L 31280:localhost:3128 SquidHost
 
在远程服务器上执行清理命令到本机 31280 端口,31280 收到的数据加密转发到 SquidHost 的 SSH Server 上,SSH Client 解密收到的数据并转发到监听的 3128 端口上,最后将 Squid 返回的数据原路 返回。
2)远程端口转发
应用场景 1:A 不能访问 C,B 能访问 A 和 C,但 A 不能访问 B,比如 A 在外网,B 在内网 在主机 B 执行:
# ssh -R 2222:主机 C:22 主机 A
将 SSH 绑定本机 2222 端口,与主机 A 建立 SSH 通道,当主机 A 访问本地 2222 端口,就等于访问主机 B 的 2222 端口,主机 B 的 2222 端口把数据转发到主机 C 的 22 端口。
应用常见 2:公司有一台内网服务器,还有一台云主机不能 SSH 直接连接这台公司内网服务器,但内 网服务器可以 SSH 连接云主机
在公司内网服务器执行:
# ssh -R 2222:localhost:22 云主机
将云主机上的 2222 端口数据转发到内网服务器 SSH Client 上,SSH Client 解密收到的数据并转发 到监听的 22 端口上,最后再将返回的数据原路返回。 3)动态端口转发(不限定端口,全权代理)
应用场景:FQ访问国外网站
如果是 MAC 系统直接在终端执行:ssh -D 2222 国外云主机
如果是 Windows 系统可借助 putty 工具实现,在 putty 里面端口转发->本地端口转发属性里面添加 一个本地端口,并勾选 SOCKS4/5 动态转发,连接即可。
将 SSH 绑定本机 8080 端口,SSH 就会创建一个 SOCKS 代理服务,直接在浏览器上设置代理本机 127.0.0.1 的 8080 端口即可,当浏览器访问国外网站时,本地代理把请求转发到国外云主机的 SSH Server,SSH 解密并转发给指定的网站。

注意:再 Linux 终端执行 ssh 绑定命令后,默认会进入一个新的 shell,只要这个 shell 不退出,此 端口转发就一直有效。如果要想放到后台执行就加-Nf 两个选项,-N 是不执行命令,-f 后台执行, 这样就转入后台运行,就可以在本地 shell 执行操作了,如果想关闭后台就 kill 这个进程。

参考资料:https://www.ibm.com/developerworks/cn/linux/l-cn-sshforward/
11.57    iptables 常见几种类型防火墙?
包过滤防火墙:包过滤是 IP 层实现,包过滤根据数据包的源 IP、目的 IP、协议类型
(TCP/UDP/ICMP)、源端口、目的端口等包头信息及数据包传输方向灯信息来判断是否允许数据包 通过。 应用层防火墙:也称为应用层代理防火墙,基于应用层协议的信息流检测,可以拦截某应用程序的 所有封包,提取包内容进行分析。有效防止 SQL 注入或者 XSS(跨站脚本攻击)之类的恶意代码。 状态检测防火墙:结合包过滤和应用层防火墙优点,基于连接状态检测机制,将属于同一连接的所 有包作为一个整体的数据流看待,构成连接状态表(通信信息,应用程序信息等),通过规则表与 状态表共同配合,对表中的各个连接状态判断。
iptables 是 Linux 下的配置防火墙的工具,用于配置 Linux 内核集成的 IP 信息包过滤系统,使增 删改查信息包过滤表中的规则更加简单。
iptables 分为四表五链,表是链的容器,链是规则的容器,规则指定动作。
四表:
filter    用于包过滤
 
nat    网络地址转发
mangle    对特定数据包修改
raw    不做数据包链接跟踪
五链:
INPUT    本机数据包入口
OUTPUT    本机数据包出口
FORWARD    经过本机转发的数据包
PREROUTING    防火墙之前,修改目的地址(DNAT)
POSTROUTING    防火墙之后,修改源地址(SNAT)
表中的链:
表    链
filter    INPUT、OUTPUT 和 FORWARD
nat    PREROUTING、POSTROUTING 和 OUTPUT
mangle    PREROUTING、POSTROUTING、INPUT、OUTPUT 和 FORWARD
raw    PREROUTING 和 OUTPUT
命令格式:iptables [-t table] 命令 [chain] 匹配条件 动作
命令    描述
-A,append    追加一条规则
-I,insert    插入一条规则,默认链头,后跟编号,指定第几条
-D,delete    删除一条规则
-F,flush    清空规则
-L,list    列出规则
-P,policy    设置链缺省规则
-m,module    模块,比如 state、multiport

匹配条件    描述
 
-i    入口网卡
-o    出口网卡
-s    源地址
-d    目的地址
-p    协议类型
--sport    源端口
--dport    目的端口

动作    描述
ACCEPT    允许数据包通过
DROP    丢弃数据包不做处理
REJECT    拒绝数据包,并返回报错信息
SNAT    一般用于 nat 表的 POSTROUTING 链,进行源地址转换
DNAT    一般用于 nat 表的 PREROUTING 链,进行目的地址转换
MASQUERADE    动态源地址转换,动态 IP 时使用

模块    描述
state    包状态,有四个:NEW、RELATED、ESTABLISHED 和 INVALID
mac    源 MAC 地址
limit    包速率限制
multiport    多端口,以逗号分隔
iprange    端口范围,以逗号分隔
示例:常用的规则配置方法
 
 

iptables -D INPUT -p tcp --dport 22:25 -j ACCEPT    # 删除这条规则
# 允许多个 TCP 端口访问
iptables -A INPUT -p tcp -m multiport --dports 22,80,8080 -j ACCEPT iptables -A INPUT -s 192.168.1.0/24 -j ACCEPT    # 允许 192.168.1.0 段 IP 访问
iptables -A INPUT -s 192.168.1.10 -j DROP    # 对 1.10 数据包丢弃
iptables -A INPUT -i eth0 -p icmp -j DROP    # eth0 网卡 ICMP 数据包丢弃,也就是禁 ping
# 允许来自 lo 接口,如果没有这条规则,将不能通过 127.0.0.1 访问本地服务 iptables -A INPUT -i lo -j ACCEPT
# 限制并发连接数,超过 30 个拒绝
iptables -I INPUT -p tcp --syn --dport 80 -m connlimit --connlimit-above 30 -j REJECT
# 限制每个 IP 每秒并发连接数最大 3 个
iptables -I INPUT -p tcp --syn -m limit --limit 1/s --limit-burst 3 -j ACCEPT
iptables -A FORWARD -p tcp --syn -m limit --limit 1/s -j ACCEPT
# iptables 服务器作为网关时,内网访问公网
iptables –t nat -A POSTROUTING -s [内网 IP 或网段] -j SNAT --to [公网 IP]
# 访问 iptables 公网 IP 端口,转发到内网服务器端口
iptables –t nat -A PREROUTING -d [对外 IP] -p tcp --dport [对外端口] -j DNAT --to [内 网 IP:内网端口]
# 本地 80 端口转发到本地 8080 端口
iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-ports 8080
# 允许已建立及该链接相关联的数据包通过
iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
# ASDL 拨号上网
iptables -t nat -A POSTROUTING -s 192.168.1.0/24 -o pppo -j MASQUERADE
# 设置 INPUT 链缺省操作丢弃所有数据包,只要不符合规则的数据包都丢弃。注意要在最后设置, 以免把自己关在外面!
iptables -P INPUT DROP



第十二章    Shell 脚本编写实战

注意事项 1)开头加解释器:#!/bin/bash
2)语法缩进,使用四个空格;多加注释说明。
3)命名建议规则:变量名大写、局部变量小写,函数名小写,名字体现出实际作用。
4)默认变量是全局的,在函数中变量 local 指定为局部变量,避免污染其他作用域。
5)有两个命令能帮助我调试脚本:set -e 遇到执行非 0 时退出脚本,set -x 打印执行过程。
6)写脚本一定先测试再到生产上。

12.1 获取随机字符串或数字

获取随机 8 位字符串:
 
 
 
获取随机 8 位数字:
 
cksum:打印 CRC 效验和统计字节

12.2   定义一个颜色输出字符串函数

 
function 关键字定义一个函数,可加或不加。
 
12.3 批量创建用户

 

12.4 检查软件包是否安装

 

12.5 检查服务状态

 
 
 

12.6 检查主机存活状态

方法 1:将错误 IP 放到数组里面判断是否 ping 失败三次
 
方法 2:将错误次数放到 FAIL_COUNT 变量里面判断是否 ping 失败三次
 
方法 3:利用 for 循环将 ping 通就跳出循环继续,如果不跳出就会走到打印 ping 失败
 
 

12.7 监控 CPU、内存和硬盘利用率

1)CPU
借助 vmstat 工具来分析 CPU 统计信息。
 
2)内存
 
 
 
3)硬盘
 

12.8 批量主机磁盘利用率监控

前提监控端和被监控端 SSH 免交互登录或者密钥登录。 写一个配置文件保存被监控主机 SSH 连接信息,文件内容格式:IP User Port
 
 
 

12.9 检查网站可用性

1)检查 URL 可用性
 
2)判断三次 URL 可用性
思路与上面检查主机存活状态一样。
 
 
 

12.10 检查 MySQL 主从同步状态

 
 
12.11   屏蔽网站访问频繁的 IP

1)屏蔽每分钟访问超过 200 的 IP
 
2)屏蔽每分钟 SSH 暴力破解超过 10 次的 IP
 
 
12.12   判断输入是否为 IP


方法 1:
function check_ip(){ IP=$1
VALID_CHECK=$(echo $IP|awk -F. \'$1<=255&&$2<=255&&$3<=255&&$4<=255{print "yes"}\') if echo $IP|grep -E "^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$">/dev/null;
 
then
 

if [ $VALID_CHECK == "yes" ]; then echo "$IP available."
else
echo "$IP not available!"
 
fi else
echo "Format error!"
fi
}
check_ip 192.168.1.1
check_ip 256.1.1.1 方法 2:
function check_ip(){
IP=$1
if [[ $IP =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]; then
FIELD1=$(echo $IP|cut -d. -f1) FIELD2=$(echo $IP|cut -d. -f2) FIELD3=$(echo $IP|cut -d. -f3) FIELD4=$(echo $IP|cut -d. -f4)
if [ $FIELD1 -le 255 -a $FIELD2 -le 255 -a $FIELD3 -le 255 -a $FIELD4 -le
255 ]; then
echo "$IP available." else
echo "$IP not available!"
fi else
echo "Format error!"
fi
}
check_ip 192.168.1.1
check_ip 256.1.1.1

增加版:加个死循环,如果 IP 可用就退出,不可用提示继续输入,并使用 awk 判断
 
 
 

12.13 判断输入是否为数字

 

12.14 找出包含关键字的文件

 
 
12.15   监控目录,将新创建的文件名追加到日志中

需安装 inotify-tools 软件包。
 

12.16 多个网卡选择


 
 
 
 
 
如果有只有一个网卡就不选择。

12.17 查看网卡实时流量

#!/bin/bash
# Description: Only CentOS6 traffic_unit_conv() {
local traffic=$1
if [ $traffic -gt 1024000 ]; then
printf "%.1f%s" "$(($traffic/1024/1024))" "MB/s" elif [ $traffic -lt 1024000 ]; then
printf "%.1f%s" "$(($traffic/1024))" "KB/s"
fi
}
NIC=$1
echo -e " In ------ Out" while true; do
OLD_IN=$(awk -F\'[: ]+\' \'$0~"\'$NIC\'"{print $3}\' /proc/net/dev) OLD_OUT=$(awk -F\'[: ]+\' \'$0~"\'$NIC\'"{print $11}\' /proc/net/dev) sleep 1
NEW_IN=$(awk -F\'[: ]+\' \'$0~"\'$NIC\'"{print $3}\' /proc/net/dev) NEW_OUT=$(awk -F\'[: ]+\' \'$0~"\'$NIC\'"{print $11}\' /proc/net/dev) IN=$(($NEW_IN-$OLD_IN))
OUT=$(($NEW_OUT-$OLD_OUT))
echo "$(traffic_unit_conv $IN) $(traffic_unit_conv $OUT)" sleep 1
done

# 也可以通过 ficonfig 命令获取收发流量 while true; do
OLD_IN=$(ifconfig $NIC |awk -F\'[: ]+\' \'/bytes/{print $4}\') OLD_OUT=$(ifconfig $NIC |awk -F\'[: ]+\' \'/bytes/{print $9}\') sleep 1
NEW_IN=$(ifconfig $NIC |awk -F\'[: ]+\' \'/bytes/{print $4}\') NEW_OUT=$(ifconfig $NIC |awk -F\'[: ]+\' \'/bytes/{print $9}\') IN=$(($NEW_IN-$OLD_IN))
OUT=$(($NEW_OUT-$OLD_OUT))
echo "$(traffic_unit_conv $IN) $(traffic_unit_conv $OUT)" sleep 1
 
 

12.18    MySQL 数据库备份

 

12.19    Nginx 启动脚本

 
 
$DAEMON -s stop sleep 1
[ ! -f $PID ] && action "* Stopping $NAME"    /bin/true || action "* Stopping
$NAME" /bin/false
}
start() {
$DAEMON
sleep 1
[ -f $PID ] && action "* Starting $NAME"    /bin/true || action "* Starting $NAME"
/bin/false
}
reload() {
$DAEMON -s reload
}
test_config() {
$DAEMON -t
}

case "$1" in
start)
if [ ! -f $PID ]; then start
 





stop)
 
else


fi
;;
 

echo "$NAME is running..." exit 0
 
if [ -f $PID ]; then stop
 
else


fi
;;
restart)
 

echo "$NAME not running!" exit 0
 
if [ ! -f $PID ]; then
echo "$NAME not running!" start
 
else


fi
;;
reload)
 

stop start
 
reload
;;
testconfig)
 
 

12.20  选择 SSH 连接主机

写一个配置文件保存被监控主机 SSH 连接信息,文件内容格式:主机名 IP User Port
 

12.21  FTP 下载文件

 
 
 

12.22   输入五个 100 数之内的字符,统计和、最小和最大

 

12.23 将结果分别赋值给变量

 
 
 

12.24 批量修改文件名

 
现在想把 article 改为 bbs:
 

12.25 统计当前目录中以.html 结尾的文件总大小

 

12.26 扫描主机端口状态

 
 
 

12.27  Expect 实现 SSH 免交互执行命令

需要先安装 expect 工具。 expect 涉及用法说明:




















方法 1:EOF 标准输出作为 expect 标准输入
 
方法 2:
 
 
方法 3:将 expect 脚本独立出来
login.exp 登录文件:
 
执行命令脚本:
 
SSH 连接信息文件:
 
 
12.28   批量修改服务器用户密码

旧密码 SSH 主机信息 old_info 文件:
 
修改密码脚本:
 
生成新密码 new_info 文件:
192.168.18.217    root    n8wX3mU%    22
192.168.18.218    root    c87;ZnnL    22

12.29 打印乘法口诀        

 
 
12.30  getopts 工具完善脚本命令行参数

getopts 是一个解析脚本选项参数的工具。 命令格式:getopts optstring name [arg] 初次使用你要注意这几点:
1)脚本位置参数会与 optstring 中的单个字母逐个匹配,如果匹配到就赋值给 name,否则赋值 name 为问号;
2)optstring 中单个字母是一个选项,如果字母后面加冒号,表示该选项后面带参数,参数值并会赋 值给 OPTARG 变量;
3)optstring 中第一个是冒号,表示屏蔽系统错误(test.sh: illegal option -- h); 4)允许把选项放一起,例如-ab 下面写一个打印文件指定行的简单例子,用于引导你思路,扩展你的脚本选项功能:
 
思路扩展:限定脚本参数,将参数保存变量,下面调用变量继续操作。