目录
前言
shell是一个用 C 语言编写的程序,它是用户使用 Linux 的桥梁。Shell 既是一种命令语言,又是一种程序设计语言。
Shell 是指一种应用程序,这个应用程序提供了一个界面,用户通过这个界面访问操作系统内核的服务。
Shell属于内置的脚本,程序开发的效率非常高,依赖于功能强大的命令可以迅速地完成开发任务(批处理)语法简单,代码写起来比较轻松,简单易学。
一、概述
(一)、shell脚本基础概念
脚本就是将手动一次性执行的命令进行规范且自动化
(二)、shell的类型
shell 命令解释环境
类型有
sh
ash
bsh
csh
bash
tcsh
dsh
zsh
在Linux系统中
文件名.sh .sh是linux下bash shell 的默认后缀
查看系统中支持的shell
cat /etc/shells
查看系统默认shell
echo $SHELL
二、Shell变量
(一)、组成
1.变量名
不会变化
声明规范
不能是数字或数字开头
以_或字母开头
变量名中不能包含特殊字符
声明方法
驼峰式 userName
双驼峰 UserName
shell写法
user_name
username
USERNAME
2.变量值
不断变化
数字、字符
(二)、类型
1.系统内置变量(环境变量)
这种变量中主要保存的是和系统操作环境相关的数据,一般对系统起作用的环境变量的变量名是系统预先设定好的。
env可在/etc/profile文件中修改
查看环境变量
echo $PATH
显示当前环境变量的值
echo $LANG
表示系统的默认语言环境为美式英语(English, United States)并使用UTF-8编码
查看当前的区域设置
locale
查看远程连接
echo $SSH_CONNECTION
2.自定义变量
这种变量是最常见的变量,由用户自由定义变量名和变量的值。
varName=varValue
等号两边不能有空格
字符串
shell中可以不使用引号
当包含有空格时,需要使用引号
引号的用法
不会引用变量值 | 单引号 ' |
会应用变量值 | 双引号 " |
引用命令结果 | 反撇号 ` |
$(命令) | 应用场景较多 |
3.预定义变量
是Bash中已经定义好的变量,变量名不能自定义,变量作用也是固定的。
$0 | 脚本本身的名称 |
$# | 脚本后参数的个数 |
$* | 脚本运行时参数的内容(整体输出) |
$@ | 脚本运行时参数的内容(逐个输出) |
$? | 脚本运行完毕后的返回值 |
默认情况 | 0 成功 |
非0 失败 |
一般情况下失败为1,特殊的失败
4.位置变量
这种变量主要是用来向脚本当中传递参数或数据的,变量名不能自定义,变量作用是固定的。
脚本后参数所在的位置
$1
...
$9
5.作用域
输出 echo $varName
默认变量只在当前shell下生效
若要在当前及其子shell下生效,需要声明为全局变量(export)
6.shell中的字符串
string
1)获得字符串的长度
语法: ${#StringName}
2)字符串取子串
语法: ${#StringName:position:lenght}
注意:lenght没有定义时,一直取到字符串的结尾!
3)字符串的截取
a.从左至右截取最后一个匹配字符串string之后的所有字符串
语法: ${StringName##*string}
b.从左至右截取第一个匹配字符串string之后的所有字符串
语法: ${StringName#*string}
c.从右至左截取最后一个匹配字符串string之后的所有字符串
语法: ${StringName%%string*}
d.从右至左截取第一个匹配字符串string之后的所有字符串
语法: ${StringName%string*}
4)字符串的拼接
语法: StringName3=${StingName1}${StringName2}
5)字符串替换:
语法: ${StringName/OldString/NewString}
三、运算符
(一)、数学运算
+ - * / % | * 作为乘号时需要加转义符为\* |
运算方法 | |
expr | expr $a + $b |
$((a+b)) | echo $((a+b)) |
$[a+b] | echo $[a+b] |
注意 | shell不支持浮点数的显示 |
\r | 回车符 |
\d | 垂直制表符 |
\v | 水平制表符 |
(二)、比较运算
1.数值比较
-eq | 等于 |
-ne | 不等于 |
-lt | 小于 |
-le | 小于等于 |
-gt | 大于 |
-ge | 大于等于 |
用test测试
2.文件比较
-e | 文件或目录是否存在 |
-f | 是否为文件 |
-d | 是否为目录 |
-r | 判断文件是否可读 |
-w | 判断文件是否可写 |
-x | 判断文件是否可执行 |
3.字符串比较
= | 字符串一致 |
!= | 字符串不一致 |
-z | 字符串为空 |
! -z | 字符串不为空 |
4.逻辑运算符
&& | 有假则假,全真为真 | |
|| | 有真则真,全假为假 | |
! | 取反 | 有真则假,有假则真 |
-a | 并且 |
-o | 或者 |
5.条件测试
&& | [ $a -ne $b ] && echo OK | 条件 && 输出结果 |
条件为真输出 | ||
|| | [ $a -ne $b ] || echo OK | 条件 || 输出结果 |
条件为假输出 |
四、shell脚本
(一)、shell脚本编写规范
第一行 | #!/bin/bash |
第二行 | #脚本的说明 |
第三行 | 脚本正文 |
(二)、shell运行规则
没有x权限 | bash 脚本所在路径/脚本文件 |
source 脚本所在路径/脚本文件 | |
.(点)脚本所在路径/脚本文件 | |
有x权限 | .(点)/脚本文件 |
脚本绝对路径/脚本文件 |
不打断会一直查看
(三)、shell脚本运行追踪
shell脚本运行追踪bash -x 脚本所在路径/脚本文件
$[$RANDOM%100]返回100内随机数
seq 1 10返回1到10 的连续数字
{1..10}返回1到10 的连续数字
seq 1.1 10.1返回1.1 2.1 3.1.... 10.1
read -p "提示语" 变量名读取键盘输入并赋值给变量名
五、shell语句
(一)、条件语句
单分支if
if [ ];then
fi
双分支if
if [ ];then
else
fi
多分支if
if [ ];then
elif [ ];then
else
fi
fi
(二)、循环语句
for
for 条件(i in 值)|((i=1;i<=10;i++))
do
语句
done
while
i=1
while 条件
do
语句
let i++(递增)
done
(三)、开关语句
case
case $1 in
条件1)
语句
;;
条件2)
语句
;;
*)
帮助信息
;;
esac
六、文件操作四剑客
(一)、正则表达式
test.sh文件
1.基础正则
a)查找特定字符
b)利用[]查找集合字符
匹配
去除
范围匹配
c)查找行首"^"与行尾"$"
以点结尾的需要转义符
d)查找任意一个字符"."与重复字符"*"
e)查找连续的字符范围"{}",需要使用转义符,"\{\}"
补wo~d中2个o,8个o
补go~d中2到无限个o
2.扩展正则
+,重复一个或一个以上的前一个字符 | cat test.txt | egrep -nE 'wo+d'或者 |
cat test.txt | egrep -n 'wo+d'(常用) | |
?,零个或者一个前一个字符 | cat test.txt | egrep -n 'bes?t' |
|,使用或者的方式找出多个字符 | cat test.txt | egrep -n 'of|is|on' |
(),查找组字符串 | cat test.txt | egrep -n 't(a|e)st' |
()+,辨别多个重复的组 | cat test.txt | egrep -n 'A(xyz)+C' |
3.常见正则表达式 (了解)
数字
“^[0-9]*[1-9][0-9]*$” //正整数
“^((-\d+)|(0+))$” //非正整数(负整数 + 0)
“^-[0-9]*[1-9][0-9]*$” //负整数
“^-?\d+$” //整数
“^\d+(\.\d+)?$” //非负浮点数(正浮点数 + 0)
“^(([0-9]+\.[0-9]*[1-9][0-9]*)|([0-9]*[1-9][0-9]*\.[0-9]+)|([0-9]*[1-9][0-9]*))$” //正浮点数
“^((-\d+(\.\d+)?)|(0+(\.0+)?))$” //非正浮点数(负浮点数 + 0)
“^(-?\d+)(\.\d+)?$” //浮点数
字符串
“^[A-Z]+$” //由26个英文字母的大写组成的字符串
“^[a-z]+$” //由26个英文字母的小写组成的字符串
“^[A-Za-z0-9]+$” //由数字和26个英文字母组成的字符串
“^\w+$” //由数字、26个英文字母或者下划线组成的字符串
Email
“^[\w-]+(\.[\w-]+)*@[\w-]+(\.[\w-]+)+$” //email地址
“^([w-.]+)@(([[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.)|(([w-]+.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(]?)$” //Email
Url
“^[a-zA-z]+://(\w+(-\w+)*)(\.(\w+(-\w+)*))*(\?\S*)?$” //url
IP
“^(d{1,2}|1dd|2[0-4]d|25[0-5]).(d{1,2}|1dd|2[0-4]d|25[0-5]).(d{1,2}|1dd|2[0-4]d|25[0-5]).(d{1,2}|1dd|2[0-4]d|25[0-5])$” //IP地址
Tel
/^((\+?[0-9]{2,4}\-[0-9]{3,4}\-)|([0-9]{3,4}\-))?([0-9]{7,8})(\-[0-9]+)?$/ //电话号码
日期校验
/^(d{2}|d{4})-((0([1-9]{1}))|(1[1|2]))-(([0-2]([1-9]{1}))|(3[0|1]))$/ // 年-月-日 yyyy-MM-dd / yy-MM-dd 格式
"^[0-9]{4}-((0([1-9]{1}))|(1[1|2]))-(([0-2]([0-9]{1}))|(3[0|1]))$" // 年-月- 日 yyyy-MM-dd 格式
/^((0([1-9]{1}))|(1[1|2]))/(([0-2]([1-9]{1}))|(3[0|1]))/(d{2}|d{4})$/ // 月/日/年
(二)、grep进阶
-r | 递归扫描指定目录下的每一个文件 |
-l | 只显示匹配到指定关键字的文件名,而不是文件内容 |
案例:查看/etc目录下所有包含bash的文件名
egrep
完美支持正则表达式
find进阶
按照权限查找 | -perm |
按照时间戳查找 | -atime |
-mtime | |
-ctime |
案例
(三)、sed
语法
sed [选项] '操作' 参数
sed [选项] -f scriptfile 参数
-e | 表示用指定命令或脚本处理 |
-f | 指定脚本文件 |
-h | 帮助 |
-n | 表示仅显示处理后的结果 |
-i | 直接编辑文本文件 |
-r | 支持扩展正则 |
操作
a | 增加,在当前行下面以行增加指定内容 |
c | 替换,将选定行替换 |
d | 删除,删除指定行 |
i | 插入,在选定行的上面插入一行 |
p | 打印 |
s | 替换,替换指定字符 |
y | 字符转换 |
案例
sed -n '3p' test.txt #打印第3行
sed -n '3,6p' test.txt #打印第3到6行的内容
sed -n 'p;n' test.txt #打印奇数行
sed -n 'n;p' test.txt #打印偶数行
sed -n '/the/p' test.txt #匹配the
nl test.txt | sed '3d' #删除第3行
nl test.txt | sed '4s/the/TTTTTT/' #替换第4行
(四)、awk
语法
awk 选项 '模式或条件{编辑命令}' 文件1 文件2 ...
awk -f 脚本文件 文件1 文件2 ...
选项
-F
指定每行的分隔符
默认分隔符为空格
内建变量
FS | 指定每行的分隔符 |
NF | 指定当前处理行的字段个数 |
NR | 当前处理行的行号 |
$0 | 当前处理行的整行内容 |
$n | 当前处理的第n个字段 |
FILENAME | 处理文件名 |
RS | 数据记录分隔,默认是\n |
案例
a)按行输出
awk '{print}' test.txt #等同cat
awk 'NR==1,NR==5{print}' test.txt #打印1到5行
awk 'NR%2==0{print}' test.txt #打印偶数行
awk 'NR%2!=0{print}' test.txt #打印奇数行
b)按段输出
ifconfig ens33 |awk '/netmask/{print $2}' 打印出netmask行的第二列
打印出uid大于等于1000的用户
统计用户组的总数
总结
今天的任务量有些重,但知识点是看懂和编辑Shell脚本的基础,需要花费时间进行反复背记,加油吧!