Shell
shell定义
Shell 是一种程序设计语言,他有变量,关键字,各种控制语句和自己的语法结构,
可以编写功能很强,代码简短的程序
#! Shebang 定义解释器
#!/usr/bin/python
#!/bin/bash
shell分类
/bin/sh
/bin/bash
/sbin/nologin
/usr/bin/sh
/usr/bin/bash
/usr/bin/nologin
默认shell : bash shell
查看当前使用的shell
echo $SHELL
shell的切换
vim /etc/passwd 编辑登录shell
bash配置文件
开机执行
/etc/rc.loacl
全局配置文件
登录执行
/etc/profile
/etc/profile.d/*.sh
/etc/bashrc
个人配置文件
~/.bash_profile -----离开时执行
~/.bashrc
登出加载的配置文件
~/.bash_logout
登陆式shell加载配置文件的过程
~/.bash_profile ---> ~/.bashrc ---> /etc/bashrc ---> /etc/profile ---> /etc/profile.d/*.sh
非登录式shell加载配置文件过程
~/.bashrc ---> /etc/bashrc ---> /etc/profile.d/*.sh
profile类的文件 : 设定环境变量
运行命令或脚本
bashrc类的文件
定义命令别名
通配符
Shell 通配符
* ? [] {}
* : 匹配所有的字符
? : 匹配任意一个字符
[] : 匹配[]中的任意一个字符
[!0-9] : 匹配除了[]中的任意字符不能是数字
{} : 匹配{}中其中一个字符串
Shell脚本规范
定义解释器
#!/bin/bash
#! Shebang
执行方式
sh bash 创建子shell执行脚本,脚本的环境变量和环境设置不会影响当前环境
. source 父shell亲自执行脚本,脚本可以改变当前的环境设置和变量
./ 需要执行权限
脚本测试
sh -x 显示所有的变量值
sh -n 检查脚本的语法是否有错误
sh 和 source的区别:
sh:当使用sh来执行脚本时,它会创建一个新的子进程来执行脚本,
并且脚本中的变量和环境设置通常不会影响当前的shell环境
source:使用source或.来执行脚本文件时,脚本中的命令会在当前Shell环境中执行,
并且脚本可以修改当前Shell的变量和环境设置。
shell变量
预定义变量
$? 最后一次执行的命令的返回状态
$$ 当前进程的进程号
$! 后台运行的最后一个进程的进程号
$# 位置参数的数量
$@ 所有位置参数的内容
$* 所有位置参数的内容
自定义变量
自定义变量
定义 : 变量名称=值
变量名称 : 只能有字母,数字.下划线组成,不能以数字开头,-波折号
=赋值符号前后不能有空格
引用变量 : $变量名 或者 ${变量名}
查看变量 :
echo $变量名
set (所有变量 : 包括自定义变量)
env (环境变量)
取消变量 :
unset 变量名 仅在当前shell中有效
作用范围 :
仅在当前shell中生效
环境变量
环境变量
shell在开始执行时已经定义好的
env 查看所有的环境变量
set 查看所有变量
环境变量拥有可继承性 : export之后就拥有继承性
export 查看变量
export 变量名=变量值 env
常用的环境变量
USER UID HOME HOSTNAME PWD PS1 PATH
PATH : 存储所有命令所在的路径
变量运算
变量运算
算式运算符
+ - * / %取余 ()
运算方式
$(()) $[] expr 运算符号左右要有空格 '*'或\*
$RANDOM 随机数
eg:
$(())
# echo $(( 5+2-(3*2)/5 ))
6
$[]
# echo $[ 5 + 2 - (3*2)/5 ]
6
expr
# expr 5 + 3
浮点运算
bash不能做小数计算:需要bc命令转换
"scale=10;3/10" | bc -l
scale : 精确值
bc -l : 数学库
变量的引用
转义 : \
一个字符被引用时,其特殊含义被禁止
"" 弱引
'' 强引
\n 换行 \t 制表符 \a 蜂鸣
read -p 打印提示信息
-t 超时时间
-s 取消回显
变量替换
${a:-xx} 若a为空或未设置,则用xx代替a进行替换,a的值不变
read -p "请输入你要符的值:" num
echo ${num:-hello}
echo $num
[root@localhost ~]# sh test.sh
请输入你要符的值:1
1
1
[root@localhost ~]# sh test.sh
请输入你要符的值:
hello
[root@localhost ~]#
${a:=xx} 若a为空或未设置,则用xx代替a进行替换,a的值改变为xx
read -p "请输入你要符的值:" num
echo ${num:=hello}
echo $num
[root@localhost ~]# sh test.sh
请输入你要符的值:1
1
1
[root@localhost ~]# sh test.sh
请输入你要符的值:
hello
hello
[root@localhost ~]#
${a:+xx} 若a设置了,则用xx代替a进行替换,a的值不变,a没设值,则为空
read -p "请输入你要符的值:" num
echo ${num:+hello}
echo $num
[root@localhost ~]# sh test.sh
请输入你要符的值:1
hello
1
[root@localhost ~]# sh test.sh
请输入你要符的值:
[root@localhost ~]#
${a:?xx} 若a为空或未设置,则xx作为标准错误打印出来,这可用来检查变量是否正确设置
匹配截取
${变量#关键词} 变量内容从左边开始符合关键词则将符合的最短数据切除
${a#*.} 切掉首个.左边的所有内容z
${变量##关键词} 变量内容从左边开始符合关键词则将符合的最长数据切除
${a##*.} 切掉最后.左边的所有内容
${变量%关键词} 变量内容从右边开始符合关键词则将符合的最短数据切除
${a%.*} 切掉首个.右边的所有内容
${变量%%关键词} 变量内容从右边开始的数据符合关键词则将符合的最长数据切除
${a%%.*} 切掉最后.右边的所有内容
${变量/旧字符串/新字符串/} 变量内容符合旧字符串则将第一个旧字符串替换位新字符串
${变量//旧字符串/新字符串/} 变量内容符合旧字符串则将全部字符串替换位新字符串
tr -d "."
echo $a | tr "." "/"
shell流程控制
测试
test 条件
条件为真返回 0,条件为假返回 1
[ 条件 ]
test 能够理解3种类型的表达式
1.文件测试
2.字符串比较
3.数字比较
字符串
-n STRING
# -n 字符串长度不为零
-z STRING
# -z 字符串长度为0
STRING1 = STRING2
# = 判断两个字符串是否一样
STRING1 != STRING2
# != 判断两个字符串是否不一样
数字
-eq 等于 -ne 不等于
-ge 大于等于 -le 小于等于
-gt 大于 -lt 小于
文件
test
-f 存在且是普通文件 # 重要
-d 存在且是目录 #
-h 存在且是符号链接
-b 块设备
-c 字符设备
-e 文件存在 #
-a && 逻辑与 and 两端的条件都可以成立
-o || 逻辑或 or 两端的条件有一段成立就行
if语句格式
if[判断条件];then
elif
else
if
case语句格式
case $变量 in
模式1)
;;
模式2)
;;
*)
;;
esac
for语句
for i in {范围}
for关键词 i变量名 in关键词 取值范围格式(空格,制表符 换行)
do
循环体
done
99乘法表
for i in {1..9}
do
for j in `seq $i`
do
echo -ne "${j}x${i}=$[$i * $j]\t"
done
echo ""
done
for i in `cat a.txt`
do
循环体 echo '$i'
done
while语句
方式一:
while 条件
while 关键字 条件 [ $1 -lt 10 ] ,while循环,条件为真的情况下,会循环
do
循环体
done
方式二:
将文本内容交给while循环,以行为单位处理,最后一行需要换行(windos创建的文件)
while read line
do
循环体
done < /文本路径
方式三 :
将文本内容交给while循环
cat aaa.txt | while read line
do
循环体
done
eg :
yum -y install `cat a.txt` | while read line
do
echo "anzhuagn $line"
done
until语句
until 条件 # 当后面的条件表达式,为假的时候进行循环,当他为真了就停止循环了。
do
循环体
done
eg :
a=0
until [ $a -gt 10 ]
do
let a++
echo $a
done
循环控制
shift
将位置参数左移一位
break
结束退出本次循环
continue
在循环中不执行continue下面的代码,转而进入下一轮循环
exit
退出脚本
函数
function
完成特定功能的代码片段
函数必须先定义才能使用
优点:避免重复的代码
unset 函数名 ---->取消函数
eg: function_name () {
list of commands
}
函数名 function_name,使用它从其他地方在脚本调用。
tput setab [1-7]---设置背景颜色
tput setaf [1-7]----设置字体颜色
tput sgr0 ---- 重置颜色
属组
books=( linux shell awk sed )
取出所有的元素
echo ${books[@]}
取出所有的索引
echo ${!books[@]}
取出索引的个数
echo ${#books[@]}
在数组中增加元素
books[4]="mysql"
修改数组中的某个值
books[0]="grep"
删除数组中的某个元素
unset books[0]
关联数组需要提前声明
declare -A my
my=([name]=newrain [sex]=man [age]=26)
echo ${my[name]}==>newrain
echo ${my[age]}==>26
echo ${!my[@]}
shell属组中"*"和"@"区别
关于在shell脚本中数组变量中 “*”跟 “@” 区别
“*”当变量加上“” 会当成一串字符串处理.
“@”变量加上“” 依然当做数组处理.
在没有加上“” 的情况下 效果是等效的.
基本正则表达式:(grep支持)
元字符
示例 功能
^ 行首定位符
^love
$ 行尾定位符
love$
. 匹配单个字符
l..e
* 匹配前导符0到多次 全部匹配 grep "o*" /etc/passwd
ab*love
.* 匹配任意多个字符 (贪婪匹配
[] 匹配方括号中任意一个字符
[lL]ove
[ - ] 匹配指定范围内的一个字符
[a-z0-9]ove
[^] 匹配不在指定组里的字符
[^a-z0-9]ove
\ 用来转义元字符
love\.
\< 词首定位符 #由数字或字母组成的
\<love
\> 词尾定位符
love\>
\(\) 匹配后的标签 # 在vim中测试
:%s@\(张三\) \(李四\) \(王五\)@ \3 \1 \2@g
拓展正则表达式:(grep -E,grep -P,egrep)
= 等于 != 不等于 =~ 匹配
扩展正则表达式元字符
+ 匹配一个或多个前导字符
[a-z]+ove
? 匹配零个或一个前导字符
lo?ve
"r.*t" 贪婪匹配
-P "r.*?" 非贪婪匹配
a|b 匹配a或b
love|hate
() 组字符loveable|rs
love(able|rs) ov+ ov+ (ov)+
(oo)+ 两个oo出现一次或者多个
(..)(..)\1\2 标签匹配字符 #
(love)able\1er
x{m} 字符x重复m次
o{5}
o{,3} 字符最多出现3次
x{m,} 字符x重复至少m次
o{5,} 字符最少出现5次
x{m,n} 字符x重复m到n次
o{5,10}
grep -E "o{3}" /etc/passwd
grep -P "\s" /etc/passwd 空格
grep -P "\d" /etc/passwd 数字
shell里面的多行注释:
shell里面的多行注释:
<!
........
!
grep
grep -E 支持拓展正则表达式
grep -E "o{3}" /etc/passwd
grep -P 支持拓展正则表达式
grep -P "\s" /etc/passwd 空格
grep -P "\d" /etc/passwd 数字
grep -v :取反
ps -ef | grep nginx | grep -v grep
grep -i : 忽略大小写
grep -i "ROOT" /etc/passwd
grep -c :统计次数
grep -i -c"ROOT" /etc/passwd
grep -o :只显示匹配到的内容
grep -o "root" /etc/passwd
grep -F|fgrep 精准匹配,不支持任何的特殊字符
fgrep "[shell]" /opt/passwd ==>看到什么过滤什么 不用考虑正则表达式
grep -r 递归过滤
sed
前面两个斜杠中是要匹配的内容,可以使用正则,后面两个斜杠中间,是要替换的内容,是纯文本
将表准输出| sed 参数 模式
sed 's/要替换的内容/替换后的内容/' file.txt
sed -f 指定一个脚本文件来处理文档,需求多的时候
sed -n 阻止输入行输出
sed -r 可以匹配到扩展正则
sed -p 打印
在文件中匹配到的删除:
sed '1d' file.txt 删除文件第一行
sed '1,2d' file.txt 删除文件的第一行到第二行
sed '2,$d' file.txt 删除第二行到最后一行
sed '/root/d' file.txt 匹配到root行,删除该行
sed '/关键字/,$d' 删除关键字所在的行到最后一行的内容
sed '1,/关键字/d' 删除第一行到关键字所在的行
sed '/关键字/,/下一个关键字/d' 删除两个关键字所在行以及中间的行
sed '/root/,2d' file.txt 匹配到root行,到第二行,删除
sed '/^$/d' file.txt 删除空行
sed '/#.*/d' file.txt 删除注释行
sed '1~2d' file.txt 删除奇数行
sed '0~2d' file.txt 删除偶数行
sed '3d;10d' file.txt 删除第三行和第十行
在文件中匹配到的部分修改文件:
sed -i 's/odler/new/g' "-i"修改后的数据会替换原文件,"-g"全局替换
sed -i.bak 's/older/new/' 在替换前会生成一个备份文件
在文件中匹配到的部分前后加上一行:
sed '/^bin/a\hello nihao/' passwd # 在匹配到开头为bin的行下一行插入内容
sed '/^bin/i\hello nihao/' passwd # 在匹配到开头为bin的行上一行插入内容
案例
修改ssh服务配置文件
1、拒绝root用户远程登录
#PermitRootLogin yes
PermitRootLogin no
sed -r 's/#PermitRootLogin.*/PermitRootLogin=no/g'
2、修改端口为22 2222
#Port 22
Port 2222
/#Port 22/a\Port 2222
3、修改dns反解析为no
#UseDNS yes
UseDNS no
/#UseDNS/a\UseDNS=no
/#UseDNS/d
2.修改nginx的配置文件
1、修改端口为88
listen 80;
listen [::] 80;
sed -r 's/Listen\s+[0-9]{2}\;/listen 88;/i' /etc/nginx/nginx.conf
2.修改网站根目录为/opt/web
sed -r 's/^[^#]\s+root\s+\/usr\/share\/nginx\/html\;/ root \/opt\/web;/' /etc/nginx/nginx.conf
sed -r s///
root /usr/share/nginx/html;
# root /usr/share/nginx/html;
/^[^#]\s+root\s+\/usr\/share\/nginx\/html\;/root \/opt\/web;/
3.修改selinux的配置
将selinux设置为永久关闭
sed -r 's/^SELINUX=.*/SELINUX=hello/' /etc/selinux/config
awk
切割字段
awk 参数 模式 文件
将标准输出|awk 参数 模式
awk BEGIN{开始处理数据前的操作,只执行一次}{处理数据的操作,文本有多少行执行多少次}END{数据处理完成以后的操作,执行一次}
参数
-F 指定分隔符
FS 指定输入字段分隔符 空格和tab
OFS 指定输出字段分隔符 空格和tab
RS 指定输入记录分隔符 换行
ORS 指定输出记录分隔符 换行
NR 行号
NF 列数
FNR 不同文件各自显示行号