Linux-shell编程

距离上次开新的文章已经过了四个月了.......真快
上次编辑4.14..........现在5.29............

shell基础

主要内部使用,基本不考虑效率
简化工作流程

练习: 先照着敲,然后看着代码写注释, 删掉代码看着注释写代码

shell : 命令解释器

Linux shell : BASH shell
unix shell : C Shell

控制字符

控制字符 作 用
\\ 输出\ 本身
\a 输出警告音
\b 退格键,也就是向左删除
\c 取消输出行末的换行符,和 -n 选项一致
\e Escape键
\f 换页符
\n 换行符
\r 回车键
\t 制表符 也就是Tab键
\v 垂直制表符 ??
\0nnn 按照八进制ASCII码表输出字符,其中0为数字0,nnn是三位八进制数
\xhh 按照十六进制ASCII码表输出字符,其中hh是两位十六进制数

echo命令

1.echo 命令
echo [选项] ["输出内容"] 
-e : 支持反斜线控制的字符转换 具体看上方控制字符表
-n : 取消输出后行末的换行符号
注意: 如果输出内容里面有空格需要加""

echo -e \e[1;31m   test \e[0m  解释:
\e[1; : 执行颜色输出开始
31m   : 颜色 30m 黑色; 31m红色; 32m绿色; 33m黄色;34m蓝色;35m洋红;36m青色;37m白色; \
        40开始是背景颜色
\e[0m :结束颜色输出

shell脚本的执行

#!/bin/bash
echo "hello word" 

两种执行方法:
赋予执行权限,直接运行,绝对路径/root/sh/hello.sh   相对路径./hello.sh

通过bash调用执行脚本 bash hello.sh  甚至不需要赋予执行权限

Bash的基本功能

history [选项]  //查询历史命令
-c : 清空历史命令,平常的历史命令有助于排错,但是配置mysql会在命令输入密码,所以清空
-w : 把缓存中的历史命令写入历史命令保存文件,如果不手工指定历史命令保存文件,则放入默认历史命令保存文件~/.bash_history中

/etc/profile可以设置历史命令最多存多少 HISTSIZE=1000  默认1000,可以调大,暂存在硬盘

调用历史命令
键盘上下箭头调整
!n : n是history命令中的标号,适用于隔了好几个命令的输入
!! : 重复上一条命令
!字符串 :  重复最后一个开头字符串的命令 如 vim
!$ : 重复上一条命令的最后一个参数

补全,命令与文件的补全

快捷键

快捷键 作 用
ctrl+A 把光标移动到命令行开头,如果输入过长,想移动到开头使用
ctrl+E 把光标移动到命令行结尾
ctrl+C 强制终止当前命令
ctrl+L 清屏相当于clear命令
ctrl+U 删除或剪切光标之前的命令
ctrl+K 删除或剪切光标之后的命令
ctrl+Y 粘贴ctrl+U或ctrl+K剪切的内容
ctrl+R 在历史命令中搜索,按下ctrl+R之后,就会出现搜索界面,只要输入搜索内容,就会从历史命令搜索
ctrl+D 退出当前终端
ctrl+Z 暂停,并放入后台,这个快捷键牵扯工作管理的内容,在系统管理详细介绍
ctrl+S 暂停屏幕输出
ctrl+Q 恢复屏幕输出

输入输出重定向

1.bash的标准输入输出

设备 设备文件名 文件描述符 类型
键盘 /dev/stdin 0 标准输入
显示器 /dev/stdout 1 标准输出
显示器 /dev/stderr 2 标准错误输出

2.输出重定向 常见

类型 符号 作用
标准输出重定向 命令 >文件 以覆盖的方式,把命令的正确输出输出到指定的文件或设备中
命令 >>文件 以追加的方式,把命令的正确输出输出到指定的文件或设备中
标准错误输出重定向 错误命令 2>文件 以覆盖的方式,把命令的错误输出输出到指定的文件或设备中
错误命令 2>>文件 以追加的方式,把命令的错误输出输出到指定的文件或设备中
正确错误输出all save 命令 > 文件 2>&1 以覆盖的方式,把正确输出和错误的输出都保存到同一个文件中
*命令 >>文件 2>&1 以追加的方式,把正确输出和错误的输出都保存到同一个文件中
命令 &> 文件 以覆盖的方式,把正确输出和错误的输出都保存到同一个文件中
*命令 &>> 文件 以追加的方式,把正确输出和错误的输出都保存到同一个文件中
*命令 >> 文件1 2 >>文件2 把正确的输出追加到文件1中,把错误的输出追加到文件2中
*为常用

3.输入重定向 不常见

wc < 1.txt   // 统计 1.txt的字节 单词数 和行数, 正常就是不加<  只有打补丁或者及其偶尔用得到

wc << zyx
>aslkdjflksadjf
>aslkdfjlsakdjflasdf
>aslkdjflkasdjflsak
>zyx
// zyx为停止符,统计这一段有多少字节, 单词数 行数, <<没啥用

多命令顺序执行

多命令执行符 格式 作 用
; 命令1 ; 命令2... 多个命令顺序执行,命令之间没有任何逻辑联系,就算前面出错后面也会继续执行
&& 命令1 && 命令2... 当命令1正确执行(($?=0) 则命令2才会执行; 当命令1执行不正确($?≠0) 则命令2不会执行
|| 命令1 || 命令2 ... 当命令1 执行不正确 ($?≠0),则命令2才会执行; 当命令1正确执行($?=0),则命令2不会执行

ls && echo yes || echo no
单分支判断语句

bash中的特殊符号

符号 作用
'' 单引号,在单引号中的所有特殊符号,如'$'和' ` '(反引号)都没有特殊含义
"" 双引号,在双引号中特殊字符都没有特殊含义,但是"$"调用变量的值, "`"引用命令, 和"\"转义符例外
`` 反引号,反引号括起来的内容是系统命令,在bash中会先执行它,和$()作用一样,不过推荐使用$(),因为反引号容易看错
$() 和反引号作用一样,用来引用系统命令
() 用于一串命令执行时,()中的命令会在 子shell 中运行 局部变量, 临时变量
{} 用于一串命令执行时,{}中的命令会在当前shell中执行,也可用于变量变形与替换
[] 用于变量的测试 后面会讲
# 注释,在shell脚本中,#开头的行代表注释
$ 调用变量的值,如需要调用变量name的值时,需要用$name的方式得到变量的值
\ 转义符,跟在\之后的特殊符号将失去特殊含义,变为普通字符,如果\$将输出$符号,而不是当作变量引用
()和{}的区别:  不常用
-()执行一串命令时,需要重新开一个子shell进行执行 
-{}执行一串命令时,是在当前shell执行
-(){}都是把一串命令放在括号里,并且命令之间用;号隔开
-()最后一个命令可以不用;号
-{}最后一个命令要用;号
-{}的第一个命令和左括号之间必须要有一个空格
-()里的命令不需要和括号有空格
-(){}中括号里面的某个命令的重定向只影响该命令,但括号外的重定向则影响到括号里的所有命令

变量

变量的定义

-变量名称可以由字母、数字和下划线组成,但是不能以数字开头。如果变量名是“2name” 则是错误的。
-在Bash中,变量的默认类型都是字符串型,如果要进行数值运算,则必修指定变量类型为 数值型。
-变量用等号连接值,等号左右两侧不能有空格。
-变量的值如果有空格,需要使用单引号或双引号包括。如:“test=" hello world!"”。其 中双引号括起来的内容“$”、“\”和反引号都拥有特殊含义,而单引号括起来的内容都是 普通字符。
-在变量的值中,可以使用“\”转义符。
-如果需要增加变量的值,那么可以进行变量值的叠加。不过变量需要用双引号包含"$变量名 或用${变量名}包含变量名
-定义变量不需要加$,使用变量时需要加$

例如:
test=123
test="$test"456  // 用这个
echo $test
123456
test=${test}789  // 别扭
echo $test789
123456789

如果把命令的结果作为变量赋值变量,则需要使用反引号或 $()包括命令:
test=$(date)
echo $test
2021年4月12日13点59分

变量的分类

- 用户自定义变量这种变量是最常见的变量,由用户自由定义变量名和变量的值
- 环境变量:这种变量中主要保存的是和系统操作环境相关的数据,比如当前登录用户,用户的家目录,命令的提示符等。不是太好理解吧,那么大家还记得在 Windows中,同一台电脑可以有多个用户登录,而且每个用户都可以定义自己的桌面样式和分辨率,这些其实就是Windows的操作环境,可以当做是 Windows的环境变量来理解。环境变量的变量名可以自由定义,但是一般对系统起作用的环境变量的变量名是系统预先设定好的
- 位置参数变量:这种变量主要是用来向脚本当中传递参数或数据的,变量名不能自定义,变量作用是固定的。
- 预定义变量:是Bash中已经定义好的变量,变量名不能自定义,变量作用也是固定的。

变量分类 名称 作用 内容
用户自定义变量 自定义 自定义 只能在本shell生效 自定义
用户自定义环境变量 大写 自定义 自定义 可以在子shell生效 自定义
系统自带环境变量 大写 确定 确定 自定义
*位置参数变量 确定 确定 自定义
*预定义变量 确定 确定 自定义

用户自定义变量

查看
set [选项]
-u : 调用未声明变量时会报错
-x : 在命令执行之前,会把命令先输出一次 不建议
// 什么都不加那就查看系统所有变量

env 也能查看环境变量

删除
unset 变量名  // 删除变量

环境变量

用户自定义环境变量:
export AGE="22"
用export声明的变量即时环境变量 删除也是unset
实际使用了declare -x 这相当于简化版

系统环境变量:
-- PATH环境变量: 系统查找命令的路径
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin
// PATH变量的值是用':'分割路径,这些路径就是系统查找命令的路径,也就是说但我们输入了一个程序名,如果没有写入路径,下体哦那个就会到PATH变量定义的路径中去寻找,是否有可以只能怪的程序,如果找到则执行,否则会报'命令没有发现'的错误

临时生效
// 把脚本拷贝到PATH变量等一的路径中,我们自己写的脚本也可以不输入路径直接运行
cp  test.sh /usr/bin
// 也可以修改PATH变量的值,而不是把程序脚本复制到PATH的路径中,使用叠加变量
PATH="$PATH": 你想放的绝对路径

永久生效:
待补充


-- PS1环境变量: 命令提示符设置
PS1='[\u@\h \W]\$] '
\d:显示日期,格式为“星期月日”
\H:显示完整的主机名。如默认主机名“1 Localhost.1 ocaldomain”
\h:显示简写主机名。如默认主机名“1 localhost
\t:显示24小时制时间,格式为“HH:MM:SS”
\T:显示12小时制时间,格式为“HH:MM:SS”
\A:显示24小时制时间,格式为“HH:MM”
\@:显示12小时制时间,格式为“HH:MMam/pm
\u:显示当前用户名
\v:显示Bash的版本信息
\w:显示当前所在目录的完整名称
\W:显示当前所在目录的最后一个目录
\#:执行的第几个命令
\$:提示符。如果是root用户会显示提示符为“#”,如果是普通用户会显示提示符为$
永久生效:
/etc/profile.d/env.sh文件下

-- LANG 语系变量
echo $LANG  // 查询当前语言
locale // 查询语系   -a 看全部
/etc/sysconfig/i18n 文件下修改
LANG="zh_CN.UTF-8"   来定义系统默认语言
  linux 中文支持
   安装了中文字体和编码
   操作终端必须支持中文编码

位置参数变量

位置参数变量 作 用
$n n为数字,$0代表命令本身,$1-$9代表第1-9个参数,10以上的参数需要用大{},如${10}
$* 代表命令行中所有的参数,$*把所有的参数看成一个整体
$@ 也代表命令行中所有的参数,不过$@把每个参数区分对待
$# 这个变量代表命令行中所有从参数的个数
#!/bin/bash // 脚本必加
a=$1 // 脚本后的第一个参数
b=$2 // 脚本后的第二个参数
sum=$(($a + $b ))  // $双小于号 进行数字运算
echo $sum // 输出 sum
------------------------------------------------------------------
chmod 755 count.sh 
./count.sh 11 22
33
------------------------------------------------------------------
只给作者用没有提示,之后学read就会有提示了
#!/bin/bash
echo "\$* is $*"
echo "\$@ is $@"
echo "\$# is $*"
--------------------------------
./para.sh 11 22 33 44
$* is 11 22 33 44  // 乍看这俩一样
$@ is 11 22 33 44  // 乍看这俩一样
$# is 4  // 统计个数
=================================
#!/bin/bash
for i in "$*"    // 循环, 因为$*把参数看作一个整体,所以执行一次就结束了
// shell语言的for in 后面有几个数就循环几次
  do
    echo $i
  done
for y in "$@"  // 循环, 因为$@把参数当成个体,所以会执行多次(当参数有多个时)
  do // 类似于 {
    echo $y
  done // 类似于 }
--------------------------------
./para2.sh 11 22 33 44
11 22 33 44
11
22
33
44

预定义变量

预定义变量 作用
$? 最后一次执行的命令的返回状态,如果这个变量的值为0,证明上一个命令正确执行,如果非0,则上一个命令不正确
$$ 当前进程的进程号 PID
$! 后台运行的最后一个进程的进程号

接受键盘输入read

read [选项] [变量名]  // 适合让用户进行输入
-p "提示信息" : 在等待read输入时,输出提示信息
-t 秒数 : read命令会一直等待用户输入,使用此选项可以指定等待时间
-n 字符数 : read命令只接受指定的字符数,就会执行
-s : 隐藏输入的数据,适用于机密信息输入

变量名: 
变量名可以自定义,如果不指定变量名,会把输入保存入默认变量REPLY
如果只提供了一个变量名,则整个输入行赋予该变量
如果提供了一个以上的变量名,则输入行分为若干字,一个接一个的赋予各个变量,而命令行上
$!/bin/bash
read -p "请你输入数字1:" num1
read -p "请你输入数字2:" num2

sum=$(($sum1+sum2))
echo "和为:$sum"
--------------------------------------------
./count2
请你输入数字1:11
请你输入数字2:22
和为:33

运算

声明变量declare

既然所有变量的默认类型是字符串型,那么只要我们把变量声明为整数型不就可以运算了嘛,使用declare命令就可以时限声明变量的类型

declare [+/-] [选项] 变量名
-  - : 给变量设定类型属性
-  + : 取消变量的类型属性
- -a : 将变量声明为数组型
- -i : 将变量声明为整数型(integer)
- -r : 将变量声明为只读变量,注意,一旦设置为只读属性,既不能修改变量的值,也不能删除变量,甚至不能通过+r取消只读属性
- -x : 将变量声明为环境变量 就是export命令复杂版
- -p : 显式指定变量的被声明的类型 直接-p查所有

定义数组

declare -a name[0]="sc"    // 变量后面加[]就相当于直接创建数组
name[1]="lm"    // 直接调用就可以

调用:
echo ${name} // 调用第一个  [0]
echo ${name[*]} // 调用全部,把*换成数字就是调用数组里面第几个-1 

只读变量

declare -r test
如果这个变量是在命令行声明的,重启才能消失,如果确实写入了环境变量配置文件,那就不可修改  

数值运算

常用方法:
$((运算式))  或 $[运算式] // 由于[]还有其他作用,最常用的还是$((运算式))



其他方法1:
a=11
b=22
declare -i c=$a+$b
echo $c
---------------------------------
33


其他方法2:
d=$(expr $a + $b) // 很麻烦, + 两边必须加空格
echo $d
---------------------------------
33

其他方法3:
let e=$a+$b
echo $e
---------------------------------
33

运算符与优先级

优先级 运算符 说明
13 -,+ 单目负,单目正
12 !,~ 逻辑非,按位取反或补码·
11 *,/,% 乘,除,取模
10 +,- 加,减
9 <<,>> 按位左移,按位右移
8 <=,>=,<,> 小于等于,大于等于,小于,大于
7 ==,!= 等于,不等于
6 & 按位与
5 ^ 按位异或
4 | 按位或
3 && 逻辑与
2 || 逻辑或
1 =,+=,-=,*=,%=,&=,^=,|=,<<=,>>= 赋值,赋值且运算

四则运算练习

初级:
#!/bin/bash
read -p "请你输入数字1:" num1
read -p "请你输入数字2:" num2

read -n1 -p "请你输入运算符[+-*/]:" oper
["$oper"=="+"] && echo "$(($num1+$num2))" && exit
["$oper"=="-"] && echo "$(($num1-$num2))" && exit
["$oper"=="*"] && echo "$(($num1*$num2))" && exit

["$oper"=="/"] && echo "$(($num1/$num2))" && exit
echo "请输入正确的运算符"
-------------------------------------------------------------

变量的测试与内容测试

set -u
echo $i
蒙圈

环境变量配置文件

source 配置文件
. 配置文件
// 不重启的情况下重新加载配置文件

主要生效的环境变量配置文件有以下五个:
/etc/profile
/etc/profile.d/ *.sh
/etc/bashrc
~/.bash_profile    
~/.bashrc

有两条路线,一条正常登陆路线,一条不用登陆的路线(子bash,su - user1)

用户登出登陆时,只会调用一个环境变量配置文件 ~/.bash_logout  默认没有任何内容,logout才行

~/.bash_history文件也就是历史命令保存文件

shell登陆信息
/etc/issue
// 可以支持的转义符我们可以通过man agetty命令查询  只对本地终端生效 加/l看序号

/etc/issue.net
/etc/ssh/sshd_config
  Banner /etc/issue.net
// 远程连接的时候提示消息 ,但是不可以识别\转义符的信息了

/etc/motd
// 登陆成功后显示的欢迎信息 不论本地还是远程都显示 直接写就行

定义Bash快捷键
stty 关键字 快捷键
stty -a  // 查询系统中创建的快捷键
// 可以改,但没必要

正则

大概只有shell会分两个正则
常见的是基础正则,直接grep就可以,扩展正则需要加-E或者使用egrep

基础正则

元字符 作用
* 前一个字符匹配0次或任意多次 至少要加两个字符,不然全找出来
. 匹配除了换行符外任意一个字符
^ 匹配行首
$ 匹配行尾
[] 匹配中括号中指定的任意一个字符,只匹配一个字符
[^] 匹配除中括号低字符意外的任意一个字符
\ 转义符,用于取消特殊符号含义
\{n\} 表示其前面的字符恰好出现n次 -E 的时候不需要加\
\{n,\} 表示其前面的字符出现不小于n次 -E 的时候不需要加\
\{n,m\} 表示其前面的字符至少出现n次,最多出现m次 -E 的时候不需要加\

正则符使用方法

grep 详细介绍 点这里

*  :
grep "saaa*id" test.txt
// 查找saa"至少两个a"id ,

.   :
grep "s..d" test.txt
// 找总共四个字母开头s结尾d中间两个任意的行

.*  :
grep ".*" test.txt  
// 匹配任意内容

^  :
grep "^A" test.txt
// 找开头第一个字母是A的行

$  :
grep "n$" test.txt
// 如果匹配以 . 结尾需要 grep "\.$" test.txt

^$  :
grep "^$" // test.txt
// 匹配空白行,  grep -v "^$" test.txt  去除文件内的空白行 -v 取反  

[]  :
grep "s[ao]id" test.txt
// 查找s和id中间 a或o  也可以中间加一个 - 表示从哪到哪 grep "s[a-z]id" 1.txt

[^]  :
grep "[^0-9]" test.txt
// 查找时不要有任意数字的行

\{n\}  :
grep "a\{3\}" test.txt
// 查找a出现至少三次的行
grep "[0-9]\{3\}" test.txt
// 查找任意数字重复三次
grep "^[0-9]\{3\}[a-z]" test.txt
// 查找开头三位数字后面时字母的行
grep"[1][3-8][0-9]\{9\}" 1.txt
// 匹配手机号

\{n,\}
grep "[0-9]\{3,\}" test.txt
// 查找任意数字重复三次以上

\{n,m\}
grep "sa\{1,3\}i" test.txt
// 查找中间有1-3个a的sai


字符串模糊查询,\{n,m\}

扩展正则

扩展元字符 作用
+ 前一个字符匹配1次或任意多次
? 前一个字符匹配0次或一次
| 匹配两个或多个分支选择
() 匹配其整体为一个字符,即模式单元,可以理解为多个单个字符组成大字符

小例子

过滤邮箱:
grep -E "[0-9a-zA-Z]+@[0-9a-zA-Z_]+(\.[0-9a-zA-Z]+){1,3}" mail.txt
过滤ip:
看着头疼

字符串处理

cut

cut [选项] 文件名    // 使用tap键分隔,cut命令不识别  空格  !!!!
-f 列号 : 提取第几列,多列用 , 逗号隔开
-d 分隔符 : 按照指定分隔符分隔列
-c 字符范围 : 不依赖分隔符来区分列,而是通过字符范围(行首为0)来进行字段提取, n-表示从第n个字符到行尾;n-m从第n个字符到第m个字符; -m表示从第一个字符到第m个字符

例子:
grep "/bin/bash" /etc/passwd | grep -v "root" | cut -d ":" -f 1,3 /etc/passwd
// 查找能登陆的用户,取反不查找root 以:为分隔符,提取/etc/passwd文件的第一列和第三列  用户名和uid

awk编程

格式化输出

printf 格式化输出
printf '输出类型输出格式' 输出    // 注意这里是单引号
输出类型:
%ns: 输出字符串,n是数字代表输出几个字符
$ni: 输出整数,n是数字代表输出几个数字
$n.mf: 输出浮点数,n和m是数字,指代输出的整数位数和小数位数,如%8.2f,代表总共输出8位,其中两位小数,6位整数
输出格式:
\a: 输出警告声音
\b: 输出退格键,也就是backspace键
\f: 清除屏幕
\n: 换行
\r: 回车,Enter键
\t: 水平输出退格键,Tab键
\v: 垂直输出退格键,Tab键

student.txt
ID	Name	PHP	Linux	MySQL	Average
1	Liming 	82	95	86	87.66
2	Sc	74	96	87	85.66
3	Tg	99	83	93	91.66

例子:
printf '%s' $(cat student.txt)  
// 这样不行 IDNamePHPLinuxMySQLAverage1Liming82958687.662Sc74968785.663Tg99839391.66
printf '%s\t %s\t %s\t %s\t %s\t %s\t \n' $(cat student.txt)
// 这就跟cat 一样了

printf '%i\t %s\t %i\t %i\t %i\t %8.2f\t \n' $(cat student.txt | grep -v Name)
// 把id号和成绩改为整型平均成绩改为浮点, 并去掉Name这一行 -bash: printf: ID: invalid number 不然会这样报错

awk基础

awk '条件1{动作1} 条件2{动作2}....' 文件名 // 在awk中使用printf需要使用 双引号 动作就是指print或printf
条件:  
  看下方的表  
动作:
  格式化输出 printf或print 这两个的区别就是一个自动加换行符,一个需要手动加
  流程控制语句

例子:
awk '{print $2 "\t" $6 }' student.txt
awk '{printf $2 "\t" $6 "\n"}' student.txt
// 列出第二列和第六列  
df -h | grep "dev/sda3" | awk '{print $5}' | cut -d "%" f 1
// 查询容量 | 提取根的行 | 取出第五列 | 以%为分隔符 提取第一列
grep -v "Name" student.txt | awk '$6>=86 {print $2,$6}'
// 取反去掉含有Name的行 | 判断第六列的数据大于等于86就打印第二列和第六列
awk '$2 ~ /Sc/ {print $6}' student.txt
// 第二列是否包含 SC 如果包含就打印第六列

实现方法:
先判断有没有BEGIN,有就先执行BEGIN,然后一行一行的处理,把整行数据赋值给$0,第一列赋值给$1,第二列赋值给$2,第三列赋值给$3......有判断条件就判断后执行 ,有END就执行END
条件的类型 条件 说明
awk保留字 BEGIN{} 在awk程序一开始时,尚未读取任何数据之前执行,BEGIN后的动作只在程序开始时执行一次
END{} 在awk程序处理完所有数据,即将结束时执行,END后的动作只在程序结束时执行一次
关系运算符 > 大于
< 小于
>= 大于等于
<= 小于等于
== 等于,用于判断两个值是否相等,如果是给变量赋值,用=
!= 不等于
A~B 判断字符串A中是否包含匹配B表达式的子字符串
A!~B 判断字符串A中是否不包含能匹配B表达式的子字符串
正则表达式 /正则/ 如果在"//"中可以写入字符,也可以支持正则表达式

awk内置变量

awk内置变量 作用
$0 代表目前awk所读入的整行数据,我们已知awk时一行一行读入数据的,$0就代表当前读入行的整行数据
$n 代表目前读入行的第n列 (字段)
*NF 当前行拥有的列数
*NR 当前awk所处理的行,是总数据的第几行
*FS 用户自定义分隔符,awk默认分隔符是任何空格,如果想要使用其他分隔符,就需要FS变量定义
ARGC 命令行参数个数
ARGV 命令好参数数组
FNR 当前文件中的当前记录数(对输入文件起始为1)
OFMT 数值的输出格式(默认为%.6g)
OFS 输出列(字段)的分隔符(默认为空格)
ORS 输出行(记录)的分隔符(默认为换行符)
RS 输入行(记录)分隔符(默认为换行符)
*为常用
进阶例子:
cat /etc/passwd | grep "/bin/bash" | awk 'BEGIN{FS=":"} $3="500" {print $1}'
// 查看 passwd文件 | 找出含有 /bin/bash的行 | awk 执行开始前 把分隔符换成 : 第三列=500 就打印第一列
cat /etc/passwd | grep "/bin/bash" | awk 'BEGIN{FS=":"}  {print $1 $1"\t" NR "\t" NF}'
// 查看 passwd文件 | 找出含有 /bin/bash的行 | awk 执行开始前 把分隔符换成 :  打印第1列 tab 当前的行 tab 总列数

sed

sed 主要是用来将数据进行选取,替换,删除,新增的命令

sed [选项] '[动作]' 文件名
选项:
  -n : 一般sed命令会把所有的数据都输出到屏幕,如果加入此选择,则只会把经过sed命令处理的行输出到屏幕
  -e : 允许对输入数据应用多条sed命令编辑,中间用 ; 隔开
  -f 脚本文件名 : 从sed 脚本中读入sed操作,和awk -f 类似
  -r : 在sed 中支持扩展正则表达式
  -i : 用sed 的修改结果直接修改读取数据的文件,而不是由屏幕输出动作
动作:
  a \ : 追加,在当前行后添加一行或多行,添加多行时,除最后一行外,每行末尾需要用 \ 代表数据未完结
  c \ : 行替换,用c后面的字符串替换原数据行,替换多行时,除最后一行外,每行末尾用 \ 代表数据未完结
  i \ : 插入,唉当前行前插入一行或多行,插入多行时,除最后一行外,每行末尾用 \ 代表数据未完结
  d : 删除 ,删除指定的行
  p : 打印输出指定的行
  s : 字符替换,用一个字符串替换另外一个字符串,格式为 " 行范围 s/旧字串/新字串/g" (和vim中的替换格式类似)


例子:
sed -n '2p' student.txt
// 不加-n 会全部输出
sed '2,4d' student.txt
// 打印剩余行,并没有写入文件
sed -i '2a 111111111111' student.txt
// 追加内容,指定行的后面,执行后不会打印出来,所以cat看一下
sed '2i hello \
> word' student.txt
// 一次添加多行
sed '3c 4 zyx 11 22 33 22' student.txt
// 替换,把第三行换成3c 后面的内容
sed -e '3d ; 4d' student.txt
// -e多条编辑 用; 隔开 
sed -e '3d \
> 4d ' student.txt
// 如果换行了可以不用写 ; 
sed 's/Lm/zyx/g' student.txt
// 字符替换
sed '4s/^/#/g' student.txt
// 替换行首为# 也就是注释指定行

sort

排序命令sort

sort [选项] 文件名
-f : 忽略大小写
-b : 忽略每行前面的空白部分
-n : 以数值型进行排序,默认使用字符串型排序
-r : 反向排序
-u : 删除重复行,就是uniq命令
-t : 指定分隔符,默认分隔符是制表符 tap
-k : 指定字段,是一个范围,如果第三列就是 -k 3,3 

例子:
sort /etc/passwd
// 直接排序,按每行第一个字符来排序
sort -t ":" -k 3,3 -n /etc/passwd

uniq [选项] 文件名 
-i : 忽略大小写
// 用来取消重复行的命令,和sort -u一样

条件判断

test

按照文件类型进行判断*

测试选项 作用
-b 文件 判断该文件是否存在,并且是否为块设备文件,是就为真
-c 文件 判断该文件是否存在,并且是否为字符设备文件,是就为真
-d 文件* 判断该文件是否存在,并且是否为目录文件,是就为真
-e 文件* 判断该文件是否存在,是就为真
-f 文件* 判断该文件是否存在,并且是否为普通文件,是就为真
-L 文件* 判断该文件是否存在,并且是否为符号链接文件,是就为真
-p 文件 判断该文件是否存在,并且是否为管道文件,是就为真
-s 文件 判断该文件是否存在,并且是否为非空,非空为真
-S 文件 判断该文件是否存在,并且是否为套接字文件 ,是为真
*为常用
 [ -e ip.txt]  或者 test -e ip.txt
echo $?  // 查看上一条命令执行结果
0  // 0为成功,非零为失败

按照文件权限进行判断*

测试选项 作用
-r 文件 判断该文件是否存在,并且是否该文件拥有读权限 r 有为真
-w 文件 判断该文件是否存在,并且是否该文件拥有写权限 w 有为真
-x 文件 判断该文件是否存在,并且是否该文件拥有执行权限 x 有为真
-u 文件 判断该文件是否存在,并且是否该文件拥有SUID权限 有为真
-g 文件 判断该文件是否存在,并且是否该文件拥有SGID权限 有为真
-k 文件 判断该文件是否存在,并且是否该文件拥有SBit权限 有为真

两个文件直接比较

测试选项 作用
文件1 -nt 文件2 判断文件1的修改时间是否比文件2的新 新则为真
文件1 -ot 文件2 判断文件1的修改时间是否比文件2的旧 旧则为真
文件1 -ef 文件2 判断文件1 是否和文件2的Inode号一致,可以理解为两个文件是否为同一个文件,判断硬链接

两个整数之间比较*

测试选项 作用
整数1 -eq 整数2 判断整数1是否和整数2相等 相等为真
整数1 -ne 整数2 判断整数1是否和整数2不相等, 不相等为真
整数1 -gt 整数2 判断整数1是否大于整数2,大于为真
整数1 -lt 整数2 判断整数1是否小于整数2,小于为真
整数1 -ge 整数2 判断整数1是否大于等一整数2 ,大于等于为真
整数1 -le 整数2 判断整数1是否小于等于整数2

字符串判断*

测试选项 作用
-z 字符串 判断字符串是否为空 为空为真
-n 字符串 判断字符串是否为非空 非空为真
字串1 == 字串2 判断字符串1是否和字符串2相等 相等为真
字串1!=字串2 判断字符串1是否和字符串2 不相等 不相等为真

多重条件判断*

测试选项 作用
判断1 -a 判断2 逻辑与,判断1和判断2都为真,最终结果才为真
判断1 -o 判断2 逻辑或,判断1 和判断2 有一个成立,最终结果就为真
! 判断 逻辑非,使原始的判断式取反

流程控制语句

if条件判断

单分支if条件语句

if [ 条件判断式 ] ; then
  程序
fi
注意:
- if语句使用fi结尾,和一般语言使用大括号的结尾不同
- [ 条件判断式 ] 就是使用test命令判断,所以中括号和条件判断式之间必须有空格
- then后面跟符合条件之后执行的程序,可以放在[]之后,用 ; 分隔,也可以换行写入
if [条件判断式 ] 
  then 
  程序
fi

例子:
判断根目录使用率超过了80%
#!/bin/bash
aa=$(df -h | grep /dev/sda3 | awk ' {print $5}' | cut -d "%" -f 1)
if [ "$aa" -ge 80 ]
  then
    echo "根分区占用率已经超过了80 ,请注意"
if

双分支if条件语句

if [ 田间判断式 ] 
  then
    条件成立时, 执行的程序
  else 
    条件不成立时,执行的另一个程序
fi

例子:
数据库mysql备份
#!/bin/bash
ntpdate asia.pool.ntp.org &>/dev/null
#同步系统时间
date=$(date +%y%m%d)
# 把当前系统时间按照 年月日格式赋予变量date
size=$(du -sh /var/lib/mysql)
$ 统计mysql数据库的大小
if [ -d /tmp/dbbak ]
# 判断备份目录是否存在,是否为目录
  then
    #如果判断为真,执行以下脚本
    echo " Date : $date!" > /tmp/dbbak/dbifo.txt
    echo " Date size : $size" >> /tmp/dbbak/dbifo.txt
    # 把当前日期和数据库大小保存入临时文件
    cd /tmp/dbbak
    # 进入备份目录
    tar -zcf mysql-lib-$date.tar.gz /var/lib/mysql dbinfo.txt &>/dev/null
    # 打包压缩数据库与临时文件,把所有输出丢入垃圾箱(不想看到任何正确输出,如果出现输出就是报错)
    rm -rf /tmp/dbbak/dbinfo.txt
    # 删除临时文件
  else
    mkdir /tmp/dbbak
    # 如果判断为假,则建立备份目录
    echo " Date : $date!" > /tmp/dbbak/dbifo.txt
    echo " Date size : $size" >> /tmp/dbbak/dbifo.txt
    # 把当前日期和数据库大小保存入临时文件
    cd /tmp/dbbak
    # 进入备份目录
    tar -zcf mysql-lib-$date.tar.gz /var/lib/mysql dbinfo.txt &>/dev/null
    # 打包压缩数据库与临时文件,把所有输出丢入垃圾箱(不想看到任何正确输出,如果出现输出就是报错)
    rm -rf /tmp/dbbak/dbinfo.txt
    # 删除临时文件
fi

例子2:
判断apche是否启动,如果没有启动则自动启动
#!/bin/bash

aa=$( netstat -tuln | awk '{print $4}' | grep ":80$" )
if [ "$aa" == " " ]
    then
        echo " httpd is down ,must restart "
        /etc/rc.d/init.d/httpd start $> /dev/null
    else
        echo "http is ok" 
fi

 

阅读剩余
THE END