shell脚本编程:
编程语言的分类:根据运行方式
编译运行:源代码–》编译器(编译)–》程序文件
解释运行:源代码–》运行时启动解释器,又解释器边解释边运行
根据其编程过程中功能的实现是调用库还是调用外部的程序文件:、
shell脚本编程:
利用系统上的命令及编程组件进行编程;
完整编程:
利用库或编程组件进行编程;
编程模型:过程式编程语言,面向对象的编程语言
程序=指令+数据
过程式:以指令为中心来组织代码,数据是服务于代码;
顺序执行
选择执行
循环执行
代表:C,bash
对象式:以数据为中心来组织代码,围绕数据来组织指令;
类(class):实例化对象,method;
代表:Java, C++, Python
shell脚本编程:过程式编程,解释运行,依赖于外部程序文件运行;
如何写shell脚本:
脚本文件的第一行,顶格:给出shebang,解释器路径,用于指明解释执行当前脚本的解释器程序文件
常见的解释器:
#!/bin/bash
#!/usr/bin/python
#!/usr/bin/perl
文本编程器:nano
行编辑器:sed
全屏幕编程器:nano, vi, vim
shell脚本是什么?
命令的堆积;
但很多命令不具有幂等性,需要用程序逻辑来判断运行条件是否满足,以避免其运行中发生错误;
运行脚本:
(1) 赋予执行权限,并直接运行此程序文件;
chmod +x /PATH/TO/SCRIPT_FILE
/PATH/TO/SCRIPT_FILE
(2) 直接运行解释器,将脚本以命令行参数传递给解释器程序;
bash /PATH/TO/SCRIPT_FILE
注意:脚本中的空白行会被解释器忽略;
脚本中,除了shebang,余下所有以#开头的行,都会被视作注释行而被忽略;此即为注释行;
shell脚本的运行是通过运行一个子shell进程实现的;
练习1:写一个脚本,实现如下功能;
(1) 显示/etc目录下所有以大写p或小写p开头的文件或目录本身;
(2) 显示/var目录下的所有文件或目录本身,并将显示结果中的小写字母转换为大写后显示;
(3) 创建临时文件/tmp/myfile.XXXX;
bash的配置文件:
两类:
profile类:为交互式登录的shell进程提供配置
全局:对所有用户都生效;
/etc/profile
/etc/profile.d/*.sh
用户个人:仅对当前用户有效;
~/.bash_profile
功用:
1、用于定义环境变量;
2、运行命令或脚本;
bashrc类:为非交互式登录的shell进程提供配置
全局:
/etc/bashrc
用户个人:
~/.bashrc
功用:
1、定义本地变量;
2、定义命令别名;
注意:仅管理员可修改全局配置文件;
登录类型:
交互式登录shell进程:
直接通过某终端输入账号和密码后登录打开的shell进程;
使用su命令:su - USERNAME, 或者使用 su -l USERNAME执行的登录切换;
/etc/profile --> /etc/profile.d/* --> ~/.bash_profile --> ~/.bashrc --> /etc/bashrc
非交互式登录shell进程:
su USERNAME执行的登录切换;
图形界面下打开的终端;
~/.bashrc --> /etc/bashrc --> /etc/profile.d/*
运行脚本
命令行中定义的特性,例如变量和别名作用域为当前shell进程的生命周期;
配置文件定义的特性,只对随后新启动的shell进程有效;
让通过配置文件定义的特性立即生效:
(1) 通过命令行重复定义一次;
(2) 让shell进程重读配置文件;
~]# source /PATH/FROM/CONF_FILE
~]# . /PATH/FROM/CONF_FILE
bash脚本编程
脚本文件格式:
第一行,顶格:#!/bin/bash
注释信息:#
代码注释:
缩进,适度添加空白行;
语言:编程语法格式,库,算法和数据结构
编程思想:
问题空间 --> 解空间
变量:
局部变量
本地变量
环境变量
位置参数变量
特殊变量
数据类型:字符型、数值型
弱类型:字符型
算术运算:
+, -, , /, %, **
let VAR=expression
VAR=
[
e
x
p
r
e
s
s
i
o
n
]
V
A
R
=
[expression] VAR=
[expression] VAR=((expression))
VAR=
(
e
x
p
r
a
r
g
u
1
a
r
g
u
2
a
r
g
u
3
)
注
意
:
有
些
时
候
乘
法
符
号
需
要
转
义
;
增
强
型
赋
值
:
变
量
做
某
种
算
术
运
算
后
回
存
至
此
变
量
中
;
l
e
t
i
=
(expr argu1 argu2 argu3) 注意:有些时候乘法符号需要转义; 增强型赋值: 变量做某种算术运算后回存至此变量中; let i=
(exprargu1argu2argu3) 注意:有些时候乘法符号需要转义; 增强型赋值: 变量做某种算术运算后回存至此变量中; leti=i+#
let i+=#
+=,-=,=, /=, %=
自增:
VAR=
[
[
[VAR+1]
let VAR+=1
let VAR++
自减:
VAR=
[
[
[VAR-1]
let VAR-=1
let VAR–
练习:
1、写一个脚本
计算/etc/passwd文件中的第10个用户和第20个用户的id号之和;
id1=
(
h
e
a
d
−
10
/
e
t
c
/
p
a
s
s
w
d
∣
t
a
i
l
−
1
∣
c
u
t
−
d
:
−
f
3
)
i
d
2
=
(head -10 /etc/passwd | tail -1 | cut -d: -f3) id2=
(head−10 /etc/passwd∣tail−1 ∣cut −d: −f3) id2=(head -20 /etc/passwd | tail -1 | cut -d: -f3)
2、写一个脚本
计算/etc/rc.d/init.d/functions和/etc/inittab文件的空白行数之和;
grep “1*$” /etc/rc.d/init.d/functions | wc -l
条件测试:
判断某需求是否满足,需要由测试机制来实现;
如何编写测试表达式以实现所需的测试:
(1) 执行命令,并利用命令状态返回值来判断;
0:成功
1-255:失败
(2) 测试表达式
test EXPRESSION
[ EXPRESSION ]
[[ EXPRESSION ]]
注意:EXPRESSION两端必须有空白字符,否则为语法错误;
bash的测试类型:
数值测试
字符串测试
文件测试
数值测试:数值比较
-eq:是否等于; [ $num1 -eq KaTeX parse error: Expected 'EOF', got '&' at position 1950: … COMMAND1 &̲& COMMAND2 …(hostname)
[ -z “
h
o
s
t
N
a
m
e
"
−
o
"
hostName" -o "
hostName"−o"hostName” == “localhost.localdomain” -o “$hostName” == “localhost” ] && hostname www.magedu.com
脚本的状态返回值:
默认是脚本中执行的最后一条件命令的状态返回值;
自定义状态退出状态码:
exit [n]:n为自己指定的状态码;
注意:shell进程遇到exit时,即会终止,因此,整个脚本执行即为结束;
向脚本传递参数:
位置参数变量
myscript.sh argu1 argu2
引用方式:
$1, $2, …, ${10}, KaTeX parse error: Expected 'EOF', got '#' at position 169: … #̲!/bin/bash …(grep “^$”
1
∣
w
c
−
l
)
f
i
l
e
2
l
i
n
e
s
=
1 | wc -l) file2_lines=
1∣wc−l) file2lines=(grep “^$” $2 | wc -l)
echo “Total blank lines:
[
[
[file1_lines+$file2_lines]”
特殊变量:
0
:
脚
本
文
件
路
径
本
身
;
0:脚本文件路径本身;
0:脚本文件路径本身; #:脚本参数的个数;
∗
:
所
有
参
数
*:所有参数
∗:所有参数 @:所有参数
过程式编程语言的代码执行顺序:
顺序执行:逐条运行;
选择执行:
代码有一个分支:条件满足时才会执行;
两个或以上的分支:只会执行其中一个满足条件的分支;
循环执行:
代码片断(循环体)要执行0、1或多个来回;
选择执行:
单分支的if语句:
if 测试条件
then
代码分支
fi
双分支的if语句:
if 测试条件; then
条件为真时执行的分支
else
条件为假时执行的分支
fi
示例:通过参数传递一个用户名给脚本,此用户不存时,则添加之;
#!/bin/bash
#
if ! grep “^$1>” /etc/passwd &> /dev/null; then
useradd $1
echo $1 | passwd --stdin $1 &> /dev/null
echo “Add user $1 finished.”
fi
#!/bin/bash
#
if [ $# -lt 1 ]; then
echo “At least one username.”
exit 2
fi
if ! grep “^$1>” /etc/passwd &> /dev/null; then
useradd $1
echo $1 | passwd --stdin $1 &> /dev/null
echo “Add user $1 finished.”
fi
#!/bin/bash
#
if [ $# -lt 1 ]; then
echo “At least one username.”
exit 2
fi
if grep “^$1>” /etc/passwd &> /dev/null; then
echo “User $1 exists.”
else
useradd $1
echo $1 | passwd --stdin $1 &> /dev/null
echo “Add user $1 finished.”
fi
练习1:通过命令行参数给定两个数字,输出其中较大的数值;
#!/bin/bash
#
if [ $# -lt 2 ]; then
echo “Two integers.”
exit 2
fi
if [ $1 -ge $2 ]; then
echo “Max number: $1.”
else
echo “Max number: $2.”
fi
#!/bin/bash
#
if [ $# -lt 2 ]; then
echo “Two integers.”
exit 2
fi
declare -i max=$1
if [ $1 -lt $2 ]; then
max=$2
fi
echo “Max number: $max.”
练习2:通过命令行参数给定一个用户名,判断其ID号是偶数还是奇数;
练习3:通过命令行参数给定两个文本文件名,如果某文件不存在,则结束脚本执行;
都存在时返回每个文件的行数,并说明其中行数较多的文件;
练习:
1、创建一个20G的文件系统,块大小为2048,文件系统ext4,卷标为TEST,要求此分区开机后自动挂载至/testing目录,且默认有acl挂载选项;
(1) 创建20G分区;
(2) 格式化:
mke2fs -t ext4 -b 2048 -L ‘TEST’ /dev/DEVICE
(3) 编辑/etc/fstab文件
LABEL=‘TEST’ /testing ext4 defaults,acl 0 0
2、创建一个5G的文件系统,卷标HUGE,要求此分区开机自动挂载至/mogdata目录,文件系统类型为ext3;
3、写一个脚本,完成如下功能:
(1) 列出当前系统识别到的所有磁盘设备;
(2) 如磁盘数量为1,则显示其空间使用信息;
否则,则显示最后一个磁盘上的空间使用信息;
if [ $disks -eq 1 ]; then
fdisk -l /dev/[hs]da
else
fdisk -l KaTeX parse error: Double superscript at position 80: …l -1 | cut -d' '̲ -f2) …diskfile" ] && echo “Fool” && exit 1
if fdisk -l | grep “^Disk $diskfile” &> /dev/null; then
fdisk -l $diskfile
else
echo “Wrong disk special file.”
exit 2
fi
[:space:] ↩︎