1、shell简介
2、变量类型:事先确定数据的存储格式和长度
3、grep, egrep, fgrep
4、逻辑运算符
5、bash变量类型
6、条件判断
7、shell中进行算术运算:
8、文件测试
9、参数传递
一、shell简介
编译器,解释器
编程语言:机器语言、汇编语言、高级语言
静态语言:编译型语言
强类型(变量)
事先转换成可执行格式
C、C++、JAVA、C#
动态语言:解释型语言, on the fly
弱类型
边解释边执行
PHP、SHELL、python、perl
面向过程:Shell, C dev ops
面向对象: JAVA, Python, perl, C++
变量:内存空间,命名
内存:编址的存储单元
shell: 外壳
GUI:Gnome, KDE, Xfce
CLI: sh, csh, ksh, bash, tcsh, zsh
登录式shell如何读取配置文件?
/etc/profile –> /etc/profile.d/*.sh –> ~/.bash_profile –> ~/.bashrc –> /etc/bashrck
Source /etc/bashrc
非登录式shell如何配置文件?
~/.bashrc –> /etc/basrc –> /etc/profile.d/*.sh
https://blog.csdn.net/a491057947/article/details/38386923
二、变量类型:事先确定数据的存储格式和长度
字符
数值
整型
浮点型: 11.23, 1.123*10^1, 0.1123*10^2
2013/10/10, 64bit
99999: 24bit,
真、假
命令替换: $(COMMAND), 反引号:COMMAND
把命令中某个子命令替换为其执行结果的过程
file-2013-02-28-14-53-31.txt
bash支持的引号:
``: 命令替换
"": 强引用,可以实现变量替换
'': 弱引用,不完成变量替换
文件名通配, globbing
*: 任意长度的任意字符
?:任意单个字符
[ ]:匹配指定范围内的任意单个字符
[abc], [a-m], [a-z], [A-Z], [0-9], [a-zA-Z], [0-9a-zA-Z]
[:space:]:空白字符
[:punct:]:标点符号
[:lower:]:小写字母
[:upper:]: 大写字母
[:alpha:]: 大小写字母
[:digit:]: 数字
[:alnum:]: 数字和大小写字母
[^]: 匹配指定范围之外的任意单个字符
[[:alpha:]]*[[:space:]]*[^[:alpha:]]
练习:
1、创建a123, cd6, c78m, c1 my, m.z, k 67, 8yu, 789等文件;注意,以上文件是以逗号隔开的,其它符号都是文件名的组成部分;
2、显示所有以a或m开头的文件;
ls [am]*
3、显示所有文件名中包含了数字的文件;
ls [0-9]
ls [[:digit:]]
4、显示所有以数字结尾且文件名中不包含空白的文件;
ls [^[:space:]][0-9] ?????????
5、显示文件名中包含了非字母或数字的特殊符号的文件;
ls [^[:alnum:]]
三、grep, egrep, fgrep
grep: 根据模式搜索文本,并将符合模式的文本行显示出来。
pattern: 文本字符和正则表达式的元字符组合而成匹配条件
grep [options] PATTERN [FILE…]
-c :只显示匹配行的数量
-i : 忽略大小写
-n : 打印行号
-s :静默工作,不显示错误信息
-q :静默工作,不显示查找结果
-v :只显示不匹配的行
-w :等效于< >
-o:只显示被模式匹配到的字符串
-E: 使用扩展正则表达式
-A #: 显示匹配行和之后的几行
-B #: grep -i -B 2 root /etc/passwd
-C #:计算匹配项的数目
**正则表达式:**REGular EXPression, REGEXP
Basic REGEXP:基本
Extended REGEXP:扩展
元字符:
“.” 匹配任意单个字符
[]: 匹配指定范围内的任意单个字符
[^]:匹配指定范围外的任意单个字符
字符集合:[:digit:], [:lower:], [:upper:], [:punct:], [:space:], [:alpha:], [:alnum:]
匹配次数(贪婪模式):
*: 匹配其前面的字符任意次
a, b, ab, aab, acb, adb, amnb
a*b, a\?b
a.*b
.*: 任意长度的任意字符
\?: 匹配其前面的字符1次或0次
{m,n}:匹配其前面的字符至少m次,至多n次
{1,}
{0,3}
位置锚定:
^: 锚定行首,此字符后面的任意内容必须出现在行首
: 锚定行尾,此字符前面的任意内容必须出现在行尾
^
: 锚定行尾,此字符前面的任意内容必须出现在行尾 ^
: 空白行
\<或\b: 锚定词首,其后面的任意字符必须作为单词首部出现
>或\b: 锚定词尾,其前面的任意字符必须作为单词的尾部出现
分组:
()
(ab)*
后向引用
\1: 引用第一个左括号以及与之对应的右括号所包括的所有内容
\2:
\3:
He love his lover.
She like her liker.
He like his lover.
练习:
1、显示/proc/meminfo文件中以不区分大小的s开头的行;
grep -i ‘^s’ /proc/meminfo
grep ‘^[sS]’ /proc/meminfo
2、显示/etc/passwd中以nologin结尾的行;
grep ‘nologin
′/etc/passwd取出默认shell为/sbin/nologin的用户列表grep“nologin
′
/
e
t
c
/
p
a
s
s
w
d
取
出
默
认
s
h
e
l
l
为
/
s
b
i
n
/
n
o
l
o
g
i
n
的
用
户
列
表
g
r
e
p
“
n
o
l
o
g
i
n
’ /etc/passwd | cut -d: -f1
取出默认shell为bash,且其用户ID号最小的用户的用户名
grep ‘bash’ /etc/passwd | sort -n -t: -k3 | head -1 | cut -d: -f1
3、显示/etc/inittab中以#开头,且后面跟一个或多个空白字符,而后又跟了任意非空白字符的行;
grep “^#[[:space:]]{1,}[^[:space:]]” /etc/inittab
4、显示/etc/inittab中包含了:一个数字:(即两个冒号中间一个数字)的行;
(该文件主要是说明系统是从哪个级别开始启动的‘系统级别
总共7各级别级别:0 表示关机
1 单用户模式)
grep ‘:[0-9]:’ /etc/inittab
5、显示/boot/grub/grub.conf文件中以一个或多个空白字符开头的行;
grep ‘^[[:space:]]{1,}’ /boot/grub/grub.conf
6、显示/etc/inittab文件中以一个数字开头并以一个与开头数字相同的数字结尾的行;
grep ‘^([0-9]).*\1
’ /etc/passwd | sort -n -t: -k3 | head -1 | cut -d: -f1 3、显示/etc/inittab中以#开头,且后面跟一个或多个空白字符,而后又跟了任意非空白字符的行; grep “^#[[:space:]]{1,}[^[:space:]]” /etc/inittab 4、显示/etc/inittab中包含了:一个数字:(即两个冒号中间一个数字)的行; (该文件主要是说明系统是从哪个级别开始启动的‘系统级别 总共7各级别级别:0 表示关机 1 单用户模式) grep ‘:[0-9]:’ /etc/inittab 5、显示/boot/grub/grub.conf文件中以一个或多个空白字符开头的行; grep ‘^[[:space:]]{1,}’ /boot/grub/grub.conf 6、显示/etc/inittab文件中以一个数字开头并以一个与开头数字相同的数字结尾的行; grep ‘^([0-9]).*\1
’ /etc/inittab
练习:
1、找出某文件中的,1位数,或2位数;
grep ‘[0-9]{1,2}’ /proc/cpuinfo
grep –color ‘\<[0-9]{1,2}>’ /proc/cpuinfo
2、找出ifconfig命令结果中的1-255之间的整数;
3、查找当前系统上名字为student(必须出现在行首)的用户的帐号的相关信息, 文件为/etc/passwd
grep ‘^student>’ /etc/passwd | cut -d: -f3
id -u student
student1
student2
练习:分析/etc/inittab文件中如下文本中前两行的特征(每一行中出现在数字必须相同),请写出可以精确找到类似两行的模式:
l1:1:wait:/etc/rc.d/rc 1
l3:3:wait:/etc/rc.d/rc 3
grep ‘^l([0-9]):\1.*\1$’ /etc/inittab
四、逻辑运算符
逻辑:1+1>2
逻辑运算:与、或、非、异或
1: 真
0: 假
1 & 0 = 0
0 & 1 = 0
0 & 0 = 0
1 & 1 = 1
或:
非:
! 真 = 假
! 假 = 真
命令的间逻辑关系:
逻辑与: &&
第一个条件为假时,第二条件不用再判断,最终结果已经有;
第一个条件为真时,第二条件必须得判断;
逻辑或: ||
脚本:命令的堆砌,按实际需要,结合命令流程控制机制实现的源程序
测试脚本是否有语法错误:
bash -n 脚本
bash -x 脚本:单步执行
shebang: 魔数
!/bin/bash
注释行,不执行
/dev/null: 软件设备, bit bucket,数据黑洞
脚本在执行时会启动一个子shell进程;
命令行中启动的脚本会继承当前shell环境变量;
系统自动执行的脚本(非命令行启动)就需要自我定义需要各环境变量;
练习:写一个脚本,完成以下任务
1、添加5个用户, user1,…, user5
2、每个用户的密码同用户名,而且要求,添加密码完成后不显示passwd命令的执行结果信息;
3、每个用户添加完成后,都要显示用户某某已经成功添加;
useradd user1
echo “user1” | passwd –stdin user1 &> /dev/null
echo “Add user1 successfully.”
如果用户存在,就显示用户已存在;否则,就添加此用户;
id user1 && echo “user1 exists.” || useradd user1
如果用户不存在,就添加;否则,显示其已经存在;
! id user1 && useradd user1 || echo “user1 exists.”
如果用户不存在,添加并且给密码;否则,显示其已经存在;
练习,写一个脚本,完成以下要求:
1、添加3个用户user1, user2, user3;但要先判断用户是否存在,不存在而后再添加;
2、添加完成后,显示一共添加了几个用户;当然,不能包括因为事先存在而没有添加的;
3、最后显示当前系统上共有多少个用户;
练习:写一个脚本
判定命令历史中历史命令的总条目是否大于1000;如果大于,则显示“Some command will gone.”;否则显示“OK”。
[ wc -l access.log |cut -d" " -f1
-gt 10 ] && echo “xx”
五、bash变量类型:
环境变量
本地变量(局部变量)
位置变量
特殊变量
变量名称:
1、只能包含字母、数字和下划线,并且不能数字开头;
2、不应该跟系统中已有的环境变量重名;
3、最好做到见名知义;
本地变量:
set VARNAME=VALUE: 作用域为整个bash进程;
局部变量:
local VARNAME=VALUE:作用域为当前代码段;
环境变量:
作用域为当前shell进程及其子进程;
export VARNAME=VALUE
VARNAME=VALUE
export VARNAME
“导出”
位置变量:
1,
1
,
2, …
Shift
特殊变量:
?:上一个命令的执行状态返回值;程序执行,可能有两类返回值:程序执行结果程序状态返回代码(0−255)0:正确执行1−255:错误执行,1,2,127系统预留;
?
:
上
一
个
命
令
的
执
行
状
态
返
回
值
;
程
序
执
行
,
可
能
有
两
类
返
回
值
:
程
序
执
行
结
果
程
序
状
态
返
回
代
码
(
0
−
255
)
0
:
正
确
执
行
1
−
255
:
错
误
执
行
,
1
,
2
,
127
系
统
预
留
;
#
∗
∗
@
$$
$0
输出重定向:
>
>
2>
2>>
&>
撤消变量:
unset VARNAME
查看当shell中变量:
Set (可以省略)
查看当前shell中的环境变量:
printenv
env
export
六、条件判断
bash中如何实现条件判断?
单分支if语句
if 判断条件; then
statement1
statement2
…
fi
双分支的if语句:
if 判断条件; then
statement1
statement2
…
else
statement3
statement4
…
fi
多分支的if语句:
if 判断条件1; then
statement1
…
elif 判断条件2; then
statement2
…
elif 判断条件3; then
statement3
…
else
statement4
…
fi
条件测试类型:
整数测试
字符测试
文件测试
条件测试的表达式:
[ expression ]
[[ expression ]]
test expression
如果/etc/inittab文件的行数大于100,就显示好大的文件;
[ wc -l /etc/inittab | cut -d' ' -f1
-gt 100 ] && echo “Large file.”
整数比较:
-eq: 测试两个整数是否相等;比如 $A -eq $B
-ne: 测试两个整数是否不等;不等,为真;相等,为假;
-gt: 测试一个数是否大于另一个数;大于,为真;否则,为假;
-lt: 测试一个数是否小于另一个数;小于,为真;否则,为假;
-ge: 大于或等于
-le:小于或等于
练习,写一个脚本,完成以下要求:
给定一个用户:
1、如果其UID为0,就显示此为管理员;
2、否则,就显示其为普通用户;
如果 UID为0;那么
显示为管理员
否则
显示为普通用户
NAME=user16
USERID=id -u $NAME
if [ $USERID -eq 0 ]; then
echo “Admin”
else
echo “common user.”
fi
NAME=user16
if [ id -u $NAME
-eq 0 ]; then
echo “Admin”
else
echo “common user.”
fi
练习:写一个脚本
判断当前系统上是否有用户的默认shell为bash;
如果有,就显示有多少个这类用户;否则,就显示没有这类用户;
grep “bash” /etc/passwd &> /dev/null
RETVAL=
” /etc/passwd &> /dev/null RETVAL=
?
if [
RETVAL−eq0];thenifgrep“bash
R
E
T
V
A
L
−
e
q
0
]
;
t
h
e
n
i
f
g
r
e
p
“
b
a
s
h
” /etc/passwd &> /dev/null; then
提示:“引用”一个命令的执行结果,要使用命令引用;比如: RESAULTS=wc -l /etc/passwd | cut -d: -f1
;
使用一个命令的执行状态结果,要直接执行此命令,一定不能引用;比如: if id user1一句中的id命令就一定不能加引号;
如果想把一个命令的执行结果赋值给某变量,要使用命令引用,比如USERID=id -u user1
;
如果想把一个命令的执行状态结果保存下来,并作为命令执行成功与否的判断条件,则需要先执行此命令,而后引用其状态结果,如
id -u user1
RETVAL=$?
此句绝对不可以写为RETVAL=id -u user1
;
练习:写一个脚本
判断当前系统上是否有用户的默认shell为bash;
如果有,就显示其中一个的用户名;否则,就显示没有这类用户;
练习:写一个脚本
给定一个文件,比如/etc/inittab
判断这个文件中是否有空白行;
如果有,则显示其空白行数;否则,显示没有空白行。
!/bin/bash
A=grep '^$' /etc/inittab | wc -l
if [
A−gt0];thenecho“
A
−
g
t
0
]
;
t
h
e
n
e
c
h
o
“
A”
else
echo “meiyoukongbaihang”
fi
!/bin/bash
FILE=/etc/inittab
if [ ! -e
FILE];thenecho“No
F
I
L
E
]
;
t
h
e
n
e
c
h
o
“
N
o
FILE.”
exit 8
fi
if grep “^
"
"
FILE &> /dev/null; then
echo “Total blank lines: grep "^$" $FILE | wc -l
.”
else
echo “No blank line.”
fi
练习:写一个脚本
给定一个用户,判断其UID与GID是否一样
如果一样,就显示此用户为“good guy”;否则,就显示此用户为“bad guy”。
!/bin/bash
USERNAME=user1
USERID=id -u $USERNAME
GROUPID=id -g $USERNAME
if [
USERID−eq
U
S
E
R
I
D
−
e
q
GROUPID ]; then
echo “Good guy.”
else
echo “Bad guy.”
fi
进一步要求:不使用id命令获得其id号;
!/bin/bash
USERNAME=user1
if ! grep “^$USERNAME>” /etc/passwd &> /dev/null; then
echo “No such user: $USERNAME.”
exit 1
fi
USERID=grep "^$USERNAME\>" /etc/passwd | cut -d: -f3
GROUPID=grep "^$USERNAME\>" /etc/passwd | cut -d: -f4
if [
USERID−eq
U
S
E
R
I
D
−
e
q
GROUPID ]; then
echo “Good guy.”
else
echo “Bad guy.”
fi
七、shell中进行算术运算:
A=3
B=6
**1、**let 算术运算表达式
let C=
A+
A
+
B
2、
[算术运算表达式]C=
[
算
术
运
算
表
达
式
]
C
=
[
A+
A
+
B]
3、
((算术运算表达式))C=
(
(
算
术
运
算
表
达
式
)
)
C
=
((
A+
A
+
B))
**4、**expr 算术运算表达式,表达式中各操作数及运算符之间要有空格,而且要使用命令引用
C=expr $A + $B
练习:写一个脚本
给定一个用户,获取其密码警告期限;
而后判断用户密码使用期限是否已经小于警告期限;
提示:计算方法,最长使用期限减去已经使用的天数即为剩余使用期限;
如果小于,则显示“Warning”;否则,就显示“OK”。
圆整:丢弃小数点后的所有内容
!/bin/bash
W=`grep "student" /etc/shadow | cut -d: -f6`
S=`date +%s`
T=`expr $S/86400`
L=`grep "^student" /etc/shadow | cut -d: -f5`
N=`grep "^student" /etc/shadow | cut -d: -f3`
SY=$[$L-$[$T-$N]]
if [ $SY -lt $W ]; then
echo 'Warning'
else
echo 'OK'
八、文件测试:
-e FILE:测试文件是否存在
-f FILE: 测试文件是否为普通文件
-d FILE: 测试指定路径是否为目录
-r FILE: 测试当前用户对指定文件是否有读取权限;
-w FILE:测试当前用户对指定文件是否有写权限;
-x FILE: 测试当前用户对指定文件是否有执行权限;
[ -e /etc/inittab ]
[ -x /etc/rc.d/rc.sysinit ]
练习:写一个脚本
给定一个文件:
如果是一个普通文件,就显示之;
如果是一个目录,亦显示之;
否则,此为无法识别之文件;
定义脚本退出状态码
exit: 退出脚本
exit #
如果脚本没有明确定义退出状态码,那么,最后执行的一条命令的退出码即为脚本的退出状态码;
九、参数传递
./filetest.sh /etc/fstab /etc/inittab
1:/etc/fstab
1
:
/
e
t
c
/
f
s
t
a
b
2: /etc/inittab
练习:写一脚本
能接受一个参数(文件路径)
判定:此参数如果是一个存在的文件,就显示“OK.”;否则就显示”No such file.”
练习:写一个脚本
给脚本传递两个参数(整数);
显示此两者之和,之乘积;
###!/bin/bash
#
if [ $# -lt 2 ]; then
echo "Usage: cacl.sh ARG1 ARG2"
exit 8
fi
o “The sum is:
[
[
1+[
1∗
1
∗
2].”
练习:写一个脚本,完成以下任务
1、使用一个变量保存一个用户名;
2、删除此变量中的用户,并且删除其家目录;
3、显示“用户删除完成”类的信息;