函数(函数返回值,函数参数),systemd,bash数组,bash字符串处理 第16天
回顾:
sed命令、bash脚本编程
sed命令:
sed的格式如下:
sed [options] 'SCRIPT' FILE...
sed的编辑命令有:d, p, w, r, a, i, c, s, =,
sed的高级编辑命令有 n, N, h, H, g, G, p, P, x, D
bash脚本编程:
while, for, case, until
case语句格式如下:
case 变量引用 in
PAT1)
分支1
;;
PAT2)
分支2
;;
...
*)
分支n
;;
esac
case支持glob风格的通配符:
*: 任意长度任意字符;
?: 任意单个字符;
[]:指定范围内的任意单个字符;
a|b: a或b
bash中的function:函数
过程式编程:代码重用
模块化编程
结构化编程
语法一:
function f_name
{
...函数体...
}
语法二:
f_name()
{
...函数体...
}
函数只有被调用才会执行;
调用:给定函数名,在函数名出现的地方,会被自动替换为函数代码;
函数的生命周期:被调用时创建,返回时终止;
return命令返回自定义状态结果,return 0表示成功,return 1-255表示失败
例子:添加用户
#!/bin/bash
#
function adduser
{
if id $username &> /dev/null; then
echo "$username exists."
return 1
else
useradd $username
[ $? -eq 0 ] && echo "Add $username finished." && return 0
fi
}
for i in {1..10}; do
username=myuser$i
adduser #这里是函数调用
done
示例:服务脚本
#!/bin/bash
#
# chkconfig: - 88 12
# description: test service script
#
prog=$(basename $0)
lockfile=/var/lock/subsys/$prog
start()
{
if [ -e $lockfile ]; then
echo "$prog is aleady running."
return 0
else
touch $lockfile
[ $? -eq 0 ] && echo "Starting $prog finished."
fi
}
stop()
{
if [ -e $lockfile ]; then
rm -f $lockfile && echo "Stop $prog ok."
else
echo "$prog is stopped yet."
fi
}
status()
{
if [ -e $lockfile ]; then
echo "$prog is running."
else
echo "$prog is stopped."
fi
}
usage()
{
echo "Usage: $prog {start|stop|restart|status}"
}
if [ $# -lt 1 ]; then
usage
exit 1
fi
case $1 in
start)
start
;;
stop)
stop
;;
restart)
stop
start
;;
status)
status
;;
*)
usage
esac
练习:打印九九乘法表,利用函数实现;
函数返回值:
函数的执行结果返回值:
(1) 使用echo或print命令进行输出;
(2) 函数体中调用命令的执行结果;
函数的退出状态码:
(1) 默认取决于函数体中执行的最后一条命令的退出状态码,$?
(2) 自定义退出状态码:return
函数可以接受参数:
传递参数给函数:调用函数时,在函数名后面以空白分隔给定参数列表即可;例如“testfunc arg1 arg2 ...”
在函数体中当中,可使用$1, $2, ...调用这些参数;还可以使用$@, $*(参数列表), $#(参数个数)等特殊变量;
示例:添加10个用户
#!/bin/bash
#
function adduser
{
if [ $# -lt 1 ]; then
return 2
# 2: no arguments
fi
if id $1 &> /dev/null; then
echo "$1 exists."
return 1
else
useradd $1
[ $? -eq 0 ] && echo "Add $1 finished." && return 0
fi
}
for i in {1..10}; do
adduser myuser$i
done
变量作用域:
本地变量:当前shell进程;为了执行脚本会启动专用的shell进程;因此,本地变量的作用范围是当前shell脚本程序文件;
局部变量:函数的生命周期;函数结束时变量被自动销毁;
如果函数中有局部变量,其名称同本地变量;
在函数中定义局部变量的方法:
local NAME=VALUE
例如:
#!/bin/bash
declare -i global_i=5 #本地变量,定义在函数之外,作用域是整个脚本
func()
{
local local_i=90 #局部变量,定义在函数之内,作用域是整个func函数
echo "func $global_i"
echo "func $local_i"
}
echo "Main $global_i"
函数递归:
函数直接或间接调用自身;
N!=N(n-1)(n-2)...1
n(n-1)! = n(n-1)(n-2)!
例子:阶乘的例子
#!/bin/bash
#
fact() {
if [ $1 -eq 0 -o $1 -eq 1 ]; then
echo 1
else
echo $[ $1 * `fact $[$1-1]` ]
fi
}
fact 5
练习:求n阶斐波那契数列;
#!/bin/bash
#
fab()
{
if [ $1 -eq 1 ]; then
echo 1
elif [ $1 -eq 2 ]; then
echo 1
else
echo $[ $(fab $[$1-1]) + $(fab $[$1-2]) ]
fi
}
fab 7
Systemd:
程序的启动流程如下:
POST --> Boot Sequence --> Bootloader --> kernel + initramfs(initrd) --> rootfs --> /sbin/init
init程序在CentOS各个版本中是不同的:
CentOS 5中是SysV风格的 init
CentOS 6: Upstart
CentOS 7: Systemd
Systemd新特性如下:
系统引导时实现服务并行启动;
按需激活进程;
系统状态快照;
基于依赖关系定义服务控制逻辑;
systemd的核心概念:unit(单元)
配置文件进行标识和配置;文件中主要包含了系统服务、监听socket、保存的系统快照以及其它与init相关的信息;保存至如下的目录中:
/usr/lib/systemd/system/
/run/systemd/system/
/etc/systemd/system/
unit的类型:
Service unit: 文件扩展名为.service, 用于定义系统服务;
ls /usr/lib/systemd/system/*.service
Target unit: 文件扩展名为.target,用于模拟实现“运行级别”;
ls /usr/lib/systemd/system/*.target
Device unit: 文件扩展名为.device, 用于定义内核识别的设备;
Mount unit: 文件扩展名为.mount, 定义文件系统挂载点;
Socket unit: 文件扩展名为.socket, 用于标识进程间通信用的socket文件;
Snapshot unit: 文件扩展名为.snapshot, 管理系统快照;
Swap unit: 文件扩展名为.swap, 用于标识swap设备;
Automount unit: 文件扩展名为.automount,文件系统的自动挂载点;
Path unit: .path,文件扩展名为.path,用于定义文件系统中的一个文件或目录;
关键特性:
基于socket的激活机制:socket与服务程序分离;
基于bus的激活机制:
基于device的激活机制:比如,某个设备挂载进系统时,激活相关服务
基于path的激活机制:目录或文件发生变化,激活相关服务
系统快照:保存各unit的当前状态信息于持久存储设备中;
向后兼容SysV init脚本;
不兼容:
systemctl命令固定不变
非由systemd启动的服务,systemctl无法与之通信
管理系统服务:service
CentOS 7: service类型的 unit
注意:CentOS 7能兼容早期的服务脚本
命令:systemctl COMMAND name.service
例如 systemctl start httpd.service
启动:service name start ==> systemctl start name.service
停止:service name stop ==> systemctl stop name.service
重启:service name restart ==> systemctl restart name.service
状态:service name status ==> systemctl status name.service
条件式重启:service name condrestart ==> systemctl try-restart name.service
重载或重启服务:systemctl reload-or-restart name.service
重载是不关闭应用的前提下重新读取配置文件
重载或条件式重启服务:systemctl reload-or-try-restart name.service
禁止设定为开机自启:systemctl mask name.service
取消禁止设定为开机自启:systemctl unmask name.service
查看某服务当前激活与否的状态:systemctl is-active name.service
查看所有已经激活的服务:systemctl list-units --type service
查看所有服务:systemctl list-units --type service --all
设定某服务开机自启:chkconfig name on ==> systemctl enable name.service
开机禁止自启:chkconfig name off ==> systemctl disable name.service
查看所有服务的开机自启状态:chkconfig --list ==> systemctl list-unit-files --type service
查看服务是否开机自启:systemctl is-enabled name.service
其它命令:
查看服务的依赖关系:systemctl list-dependencies name.service
管理target类型的 units:
unit配置文件:.target
运行级别:
0 ==> runlevel0.target链接文件链接至poweroff.target
1 ==> runlevel1.target链接文件链接至rescue.target
2 ==> runlevel2.target链接文件链接至multi-user.target
3 ==> runlevel3.target链接文件链接至multi-user.target
4 ==> runlevel4.target链接文件链接至multi-user.target
5 ==> runlevel5.target链接文件链接至graphical.target
6 ==> runlevel6.target链接文件链接至reboot.target
级别切换:
init N ==> systemctl isolate name.target
查看级别:
runlevel ==> systemctl list-units --type target
获取默认运行级别:
/etc/inittab ==> systemctl get-default
修改默认级别:
/etc/inittab ==> systemctl set-default name.target
切换至紧急救援模式:
systemctl rescue
切换至emergency模式:
systemctl emergency
其它常用命令:
关机:systemctl halt、systemctl poweroff
重启:systemctl reboot
挂起:systemctl suspend
快照:systemctl hibernate
快照并挂起:systemctl hybrid-sleep
----------------------------------分割线----------------------------------------------------
回顾: bash脚本编程、systemd
函数:模块化编程,函数定义如下:
function f_name {
...函数体...
}
f_name() {
...函数体...
}
函数的返回:return命令
函数的参数:
函数体中调用参数:$1, $2, ...
$*, $@, $#
向函数传递参数:
函数名 参数列表
bash脚本编程:数组
变量:存储单个元素的内存空间;
数组:存储多个元素的连续的内存空间;
索引:编号从0开始,属于数值索引;
注意:索引也可支持使用自定义的格式,而不仅仅是数值格式;
bash的数组支持稀疏格式;
引用数组中的元素:${ARRAY_NAME[INDEX]} 花括号一般不可省略
声明数组:
declare -a ARRAY_NAME
declare -A ARRAY_NAME: 关联数组;key-value
数组元素的赋值:
(1) 一次只赋值一个元素;
ARRAY_NAME[INDEX]=VALUE
weekdays[0]="Sunday"
weekdays[4]="Thursday"
(2) 一次赋值全部元素:
ARRAY_NAME=("VAL1" "VAL2" "VAL3" ...)
(3) 只赋值特定元素:
ARRAY_NAME=([0]="VAL1" [3]="VAL2" ...)
(4) read -a ARRAY
引用数组元素:${ARRAY_NAME[INDEX]}
注意:省略[INDEX]表示引用下标为0的元素;
数组的长度(数组中元素的个数):${#ARRAY_NAME[*]}或者${#ARRAY_NAME[@]}
示例:生成10个随机数保存于数组中,并找出其最大值和最小值
#!/bin/bash
#
declare -a rand
declare -i max=$RANDOM
declare -i min=$max
rand[0]=$max
echo "0:${rand[0]}"
for i in {1..9}; do
rand[$i]=$RANDOM
echo "$i:${rand[$i]}"
[ ${rand[$i]} -gt $max ] && max=${rand[$i]}
[ ${rand[$i]} -lt $min ] && min=${rand[$i]}
done
echo "Max: $max"
echo "Min: $min"
练习:写一个脚本
定义一个数组,数组中的元素是/var/log目录下所有以.log结尾的文件;要统计其下标为偶数的文件中的行数之和;
#!/bin/bash
#
declare -a files
files=(/var/log/*.log) #初始化数组files
declare -i lines=0
for i in $(seq 0 $[${#files[*]}-1]); do
if [ $[$i%2] -eq 0 ];then
let lines+=$(wc -l ${files[$i]} | cut -d' ' -f1)
fi
done
echo "Lines: $lines."
引用数组中的所有元素:${ARRAY[@]}, ${ARRAY[*]}
数组切片:${ARRAY[@]:offset:number}
offset: 要跳过的元素个数
number: 要取出的元素个数
取偏移量之后的所有元素:${ARRAY[@]:offset};
向数组中追加元素:ARRAY[${#ARRAY[*]}]=value ,追加到数组尾部
删除数组中的某元素:unset ARRAY[INDEX]
关联数组:key-value
declare -A ARRAY_NAME
ARRAY_NAME=([index_name1]='val1' [index_name2]='val2' ...)
练习:生成10个随机数,升序或降序排序;
bash的字符串处理工具:
字符串切片:
${var:offset:number}
取字符串的最右侧几个字符:${var: -lengh}
注意:冒号后必须有一空白字符;
基于模式取子串:
${var#*word}:其中word可以是指定的任意字符;功能:自左而右,查找var变量所存储的字符串中,第一次出现的word, 删除字符串开头至第一次出现word字符之间的所有字符;
${var##*word}:同上,不过,删除的是字符串开头至最后一次由word指定的字符之间的所有内容;
file="/var/log/messages"
${file##*/}的结果是 messages
${var%word*}:其中word可以是指定的任意字符;功能:自右而左,查找var变量所存储的字符串中,第一次出现的word, 删除字符串最后一个字符向左至第一次出现word字符之间的所有字符;
file="/var/log/messages"
${file%/*}的结果是/var/log
${var%%word*}:同上,只不过删除字符串最右侧的字符向左至最后一次出现word字符之间的所有字符;
示例:url=http://www.magedu.com:80
${url##*:}的结果是80
${url%%:*} 的结果是http
字符串的查找替换:
${var/pattern/substi}:查找var所表示的字符串中,第一次被pattern所匹配到的字符串,以substi替换之;
${var//pattern/substi}: 查找var所表示的字符串中,所有能被pattern所匹配到的字符串,以substi替换之;全局替换
${var/#pattern/substi}:查找var所表示的字符串中,行首被pattern所匹配到的字符串,以substi替换之;
${var/%pattern/substi}:查找var所表示的字符串中,行尾被pattern所匹配到的字符串,以substi替换之;
查找并删除:
${var/pattern}:查找var所表示的字符串中,删除第一次被pattern所匹配到的字符串
${var//pattern}:查找var所表示的字符串中,删除所有被pattern所匹配到的字符串
${var/#pattern}:查找var所表示的字符串中,删除行首被pattern所匹配到的字符串,
${var/%pattern}:查找var所表示的字符串中,删除行尾被pattern所匹配到的字符串,
字符大小写转换:
${var^^}:把var中的所有小写字母转换为大写;
${var,,}:把var中的所有大写字母转换为小写;
变量赋值:
${var:-value}:如果var为空或未设置,那么返回value;否则,则返回var的值;
${var:=value}:如果var为空或未设置,那么返回value,并将value赋值给var;否则,则返回var的值;
${var:+value}:如果var不空,则返回value;
${var:?error_info}:如果var为空或未设置,那么返回error_info;否则,则返回var的值;
为脚本程序使用配置文件:步骤如下
(1) 定义文本文件,每行定义“name=value”
(2) 在脚本中source此文件即可
命令:
mktemp命令:创建临时文件或临时目录
mktemp [OPTION]... [TEMPLATE]
TEMPLATE使用filename.XXX,其中XXX至少要出现三个;
-d: 创建临时目录;
--tmpdir=/PATH/TO/SOMEDIR:指明临时文件或目录位置;
例如 mktemp /tmp/somefile.XXXX
install命令:
install [OPTION]... [-T] SOURCE DEST 单个复制文件
install [OPTION]... SOURCE... DIRECTORY 复制多个文件到目录中
install [OPTION]... -t DIRECTORY SOURCE...
install [OPTION]... -d DIRECTORY... 创建空目录
选项:
-m MODE
-o OWNER
-g GROUP
-D
例如 install -m 700 -d workspace 创建空目录workspace,并且指明权限为700
install -D /usr/sbin/ss /mnt/sysroot/usr/sbin/ss
练习:写一个脚本
(1) 提示用户输入一个可执行命令名称;
(2) 获取此命令所依赖到的所有库文件列表;
(3) 复制命令至某目标目录(例如/mnt/sysroot)下的对应路径下;
/bin/bash ==> /mnt/sysroot/bin/bash
/usr/bin/passwd ==> /mnt/sysroot/usr/bin/passwd
(4) 复制此命令依赖到的所有库文件至目标目录下的对应路径下:
/lib64/ld-linux-x86-64.so.2 ==> /mnt/sysroot/lib64/ld-linux-x86-64.so.2
进一步地:每次复制完成一个命令后,不要退出,而是提示用户键入新的要复制的命令,并重复完成上述功能;直到用户输入quit退出;
#!/bin/bash
#
if [ $# -ne 2 ] ; then
echo "usage: `basename $0` COMMAND DIRECTORY" # $1是命令,$2是一個目錄
exit 1
fi
if [ ! -e $1 ];then
echo "$1 is not a exists file"
exit 2
fi
if [ ! -d $2 ];then
echo "$2 is not a exists directory"
exit 3
fi
declare -a dep_files #dep_files 表示数组
declare -a dep_files_need
declare -i i=0
dep_files=(`ldd $1`)
#echo ${dep_files[*]}
for item in ${dep_files[*]};do
if echo $item | grep -E "^/.*so\.[0-9]$" &> /dev/null ;then
dep_files_need[i]=$item
let i+=1
fi
# echo $item
done
echo ${dep_files_need[*]}
if [ ! -e $2$1 ];then
install -D $1 $2$1
fi
for item in ${dep_files_need[*]};do
if [ ! -e $2$item ];then
install -D $item $2$item
fi
done
sed命令、bash脚本编程
sed命令:
sed的格式如下:
sed [options] 'SCRIPT' FILE...
sed的编辑命令有:d, p, w, r, a, i, c, s, =,
sed的高级编辑命令有 n, N, h, H, g, G, p, P, x, D
bash脚本编程:
while, for, case, until
case语句格式如下:
case 变量引用 in
PAT1)
分支1
;;
PAT2)
分支2
;;
...
*)
分支n
;;
esac
case支持glob风格的通配符:
*: 任意长度任意字符;
?: 任意单个字符;
[]:指定范围内的任意单个字符;
a|b: a或b
bash中的function:函数
过程式编程:代码重用
模块化编程
结构化编程
语法一:
function f_name
{
...函数体...
}
语法二:
f_name()
{
...函数体...
}
函数只有被调用才会执行;
调用:给定函数名,在函数名出现的地方,会被自动替换为函数代码;
函数的生命周期:被调用时创建,返回时终止;
return命令返回自定义状态结果,return 0表示成功,return 1-255表示失败
例子:添加用户
#!/bin/bash
#
function adduser
{
if id $username &> /dev/null; then
echo "$username exists."
return 1
else
useradd $username
[ $? -eq 0 ] && echo "Add $username finished." && return 0
fi
}
for i in {1..10}; do
username=myuser$i
adduser #这里是函数调用
done
示例:服务脚本
#!/bin/bash
#
# chkconfig: - 88 12
# description: test service script
#
prog=$(basename $0)
lockfile=/var/lock/subsys/$prog
start()
{
if [ -e $lockfile ]; then
echo "$prog is aleady running."
return 0
else
touch $lockfile
[ $? -eq 0 ] && echo "Starting $prog finished."
fi
}
stop()
{
if [ -e $lockfile ]; then
rm -f $lockfile && echo "Stop $prog ok."
else
echo "$prog is stopped yet."
fi
}
status()
{
if [ -e $lockfile ]; then
echo "$prog is running."
else
echo "$prog is stopped."
fi
}
usage()
{
echo "Usage: $prog {start|stop|restart|status}"
}
if [ $# -lt 1 ]; then
usage
exit 1
fi
case $1 in
start)
start
;;
stop)
stop
;;
restart)
stop
start
;;
status)
status
;;
*)
usage
esac
练习:打印九九乘法表,利用函数实现;
函数返回值:
函数的执行结果返回值:
(1) 使用echo或print命令进行输出;
(2) 函数体中调用命令的执行结果;
函数的退出状态码:
(1) 默认取决于函数体中执行的最后一条命令的退出状态码,$?
(2) 自定义退出状态码:return
函数可以接受参数:
传递参数给函数:调用函数时,在函数名后面以空白分隔给定参数列表即可;例如“testfunc arg1 arg2 ...”
在函数体中当中,可使用$1, $2, ...调用这些参数;还可以使用$@, $*(参数列表), $#(参数个数)等特殊变量;
示例:添加10个用户
#!/bin/bash
#
function adduser
{
if [ $# -lt 1 ]; then
return 2
# 2: no arguments
fi
if id $1 &> /dev/null; then
echo "$1 exists."
return 1
else
useradd $1
[ $? -eq 0 ] && echo "Add $1 finished." && return 0
fi
}
for i in {1..10}; do
adduser myuser$i
done
变量作用域:
本地变量:当前shell进程;为了执行脚本会启动专用的shell进程;因此,本地变量的作用范围是当前shell脚本程序文件;
局部变量:函数的生命周期;函数结束时变量被自动销毁;
如果函数中有局部变量,其名称同本地变量;
在函数中定义局部变量的方法:
local NAME=VALUE
例如:
#!/bin/bash
declare -i global_i=5 #本地变量,定义在函数之外,作用域是整个脚本
func()
{
local local_i=90 #局部变量,定义在函数之内,作用域是整个func函数
echo "func $global_i"
echo "func $local_i"
}
echo "Main $global_i"
函数递归:
函数直接或间接调用自身;
N!=N(n-1)(n-2)...1
n(n-1)! = n(n-1)(n-2)!
例子:阶乘的例子
#!/bin/bash
#
fact() {
if [ $1 -eq 0 -o $1 -eq 1 ]; then
echo 1
else
echo $[ $1 * `fact $[$1-1]` ]
fi
}
fact 5
练习:求n阶斐波那契数列;
#!/bin/bash
#
fab()
{
if [ $1 -eq 1 ]; then
echo 1
elif [ $1 -eq 2 ]; then
echo 1
else
echo $[ $(fab $[$1-1]) + $(fab $[$1-2]) ]
fi
}
fab 7
Systemd:
程序的启动流程如下:
POST --> Boot Sequence --> Bootloader --> kernel + initramfs(initrd) --> rootfs --> /sbin/init
init程序在CentOS各个版本中是不同的:
CentOS 5中是SysV风格的 init
CentOS 6: Upstart
CentOS 7: Systemd
Systemd新特性如下:
系统引导时实现服务并行启动;
按需激活进程;
系统状态快照;
基于依赖关系定义服务控制逻辑;
systemd的核心概念:unit(单元)
配置文件进行标识和配置;文件中主要包含了系统服务、监听socket、保存的系统快照以及其它与init相关的信息;保存至如下的目录中:
/usr/lib/systemd/system/
/run/systemd/system/
/etc/systemd/system/
unit的类型:
Service unit: 文件扩展名为.service, 用于定义系统服务;
ls /usr/lib/systemd/system/*.service
Target unit: 文件扩展名为.target,用于模拟实现“运行级别”;
ls /usr/lib/systemd/system/*.target
Device unit: 文件扩展名为.device, 用于定义内核识别的设备;
Mount unit: 文件扩展名为.mount, 定义文件系统挂载点;
Socket unit: 文件扩展名为.socket, 用于标识进程间通信用的socket文件;
Snapshot unit: 文件扩展名为.snapshot, 管理系统快照;
Swap unit: 文件扩展名为.swap, 用于标识swap设备;
Automount unit: 文件扩展名为.automount,文件系统的自动挂载点;
Path unit: .path,文件扩展名为.path,用于定义文件系统中的一个文件或目录;
关键特性:
基于socket的激活机制:socket与服务程序分离;
基于bus的激活机制:
基于device的激活机制:比如,某个设备挂载进系统时,激活相关服务
基于path的激活机制:目录或文件发生变化,激活相关服务
系统快照:保存各unit的当前状态信息于持久存储设备中;
向后兼容SysV init脚本;
不兼容:
systemctl命令固定不变
非由systemd启动的服务,systemctl无法与之通信
管理系统服务:service
CentOS 7: service类型的 unit
注意:CentOS 7能兼容早期的服务脚本
命令:systemctl COMMAND name.service
例如 systemctl start httpd.service
启动:service name start ==> systemctl start name.service
停止:service name stop ==> systemctl stop name.service
重启:service name restart ==> systemctl restart name.service
状态:service name status ==> systemctl status name.service
条件式重启:service name condrestart ==> systemctl try-restart name.service
重载或重启服务:systemctl reload-or-restart name.service
重载是不关闭应用的前提下重新读取配置文件
重载或条件式重启服务:systemctl reload-or-try-restart name.service
禁止设定为开机自启:systemctl mask name.service
取消禁止设定为开机自启:systemctl unmask name.service
查看某服务当前激活与否的状态:systemctl is-active name.service
查看所有已经激活的服务:systemctl list-units --type service
查看所有服务:systemctl list-units --type service --all
设定某服务开机自启:chkconfig name on ==> systemctl enable name.service
开机禁止自启:chkconfig name off ==> systemctl disable name.service
查看所有服务的开机自启状态:chkconfig --list ==> systemctl list-unit-files --type service
查看服务是否开机自启:systemctl is-enabled name.service
其它命令:
查看服务的依赖关系:systemctl list-dependencies name.service
管理target类型的 units:
unit配置文件:.target
运行级别:
0 ==> runlevel0.target链接文件链接至poweroff.target
1 ==> runlevel1.target链接文件链接至rescue.target
2 ==> runlevel2.target链接文件链接至multi-user.target
3 ==> runlevel3.target链接文件链接至multi-user.target
4 ==> runlevel4.target链接文件链接至multi-user.target
5 ==> runlevel5.target链接文件链接至graphical.target
6 ==> runlevel6.target链接文件链接至reboot.target
级别切换:
init N ==> systemctl isolate name.target
查看级别:
runlevel ==> systemctl list-units --type target
获取默认运行级别:
/etc/inittab ==> systemctl get-default
修改默认级别:
/etc/inittab ==> systemctl set-default name.target
切换至紧急救援模式:
systemctl rescue
切换至emergency模式:
systemctl emergency
其它常用命令:
关机:systemctl halt、systemctl poweroff
重启:systemctl reboot
挂起:systemctl suspend
快照:systemctl hibernate
快照并挂起:systemctl hybrid-sleep
----------------------------------分割线----------------------------------------------------
回顾: bash脚本编程、systemd
函数:模块化编程,函数定义如下:
function f_name {
...函数体...
}
f_name() {
...函数体...
}
函数的返回:return命令
函数的参数:
函数体中调用参数:$1, $2, ...
$*, $@, $#
向函数传递参数:
函数名 参数列表
bash脚本编程:数组
变量:存储单个元素的内存空间;
数组:存储多个元素的连续的内存空间;
索引:编号从0开始,属于数值索引;
注意:索引也可支持使用自定义的格式,而不仅仅是数值格式;
bash的数组支持稀疏格式;
引用数组中的元素:${ARRAY_NAME[INDEX]} 花括号一般不可省略
声明数组:
declare -a ARRAY_NAME
declare -A ARRAY_NAME: 关联数组;key-value
数组元素的赋值:
(1) 一次只赋值一个元素;
ARRAY_NAME[INDEX]=VALUE
weekdays[0]="Sunday"
weekdays[4]="Thursday"
(2) 一次赋值全部元素:
ARRAY_NAME=("VAL1" "VAL2" "VAL3" ...)
(3) 只赋值特定元素:
ARRAY_NAME=([0]="VAL1" [3]="VAL2" ...)
(4) read -a ARRAY
引用数组元素:${ARRAY_NAME[INDEX]}
注意:省略[INDEX]表示引用下标为0的元素;
数组的长度(数组中元素的个数):${#ARRAY_NAME[*]}或者${#ARRAY_NAME[@]}
示例:生成10个随机数保存于数组中,并找出其最大值和最小值
#!/bin/bash
#
declare -a rand
declare -i max=$RANDOM
declare -i min=$max
rand[0]=$max
echo "0:${rand[0]}"
for i in {1..9}; do
rand[$i]=$RANDOM
echo "$i:${rand[$i]}"
[ ${rand[$i]} -gt $max ] && max=${rand[$i]}
[ ${rand[$i]} -lt $min ] && min=${rand[$i]}
done
echo "Max: $max"
echo "Min: $min"
练习:写一个脚本
定义一个数组,数组中的元素是/var/log目录下所有以.log结尾的文件;要统计其下标为偶数的文件中的行数之和;
#!/bin/bash
#
declare -a files
files=(/var/log/*.log) #初始化数组files
declare -i lines=0
for i in $(seq 0 $[${#files[*]}-1]); do
if [ $[$i%2] -eq 0 ];then
let lines+=$(wc -l ${files[$i]} | cut -d' ' -f1)
fi
done
echo "Lines: $lines."
引用数组中的所有元素:${ARRAY[@]}, ${ARRAY[*]}
数组切片:${ARRAY[@]:offset:number}
offset: 要跳过的元素个数
number: 要取出的元素个数
取偏移量之后的所有元素:${ARRAY[@]:offset};
向数组中追加元素:ARRAY[${#ARRAY[*]}]=value ,追加到数组尾部
删除数组中的某元素:unset ARRAY[INDEX]
关联数组:key-value
declare -A ARRAY_NAME
ARRAY_NAME=([index_name1]='val1' [index_name2]='val2' ...)
练习:生成10个随机数,升序或降序排序;
bash的字符串处理工具:
字符串切片:
${var:offset:number}
取字符串的最右侧几个字符:${var: -lengh}
注意:冒号后必须有一空白字符;
基于模式取子串:
${var#*word}:其中word可以是指定的任意字符;功能:自左而右,查找var变量所存储的字符串中,第一次出现的word, 删除字符串开头至第一次出现word字符之间的所有字符;
${var##*word}:同上,不过,删除的是字符串开头至最后一次由word指定的字符之间的所有内容;
file="/var/log/messages"
${file##*/}的结果是 messages
${var%word*}:其中word可以是指定的任意字符;功能:自右而左,查找var变量所存储的字符串中,第一次出现的word, 删除字符串最后一个字符向左至第一次出现word字符之间的所有字符;
file="/var/log/messages"
${file%/*}的结果是/var/log
${var%%word*}:同上,只不过删除字符串最右侧的字符向左至最后一次出现word字符之间的所有字符;
示例:url=http://www.magedu.com:80
${url##*:}的结果是80
${url%%:*} 的结果是http
字符串的查找替换:
${var/pattern/substi}:查找var所表示的字符串中,第一次被pattern所匹配到的字符串,以substi替换之;
${var//pattern/substi}: 查找var所表示的字符串中,所有能被pattern所匹配到的字符串,以substi替换之;全局替换
${var/#pattern/substi}:查找var所表示的字符串中,行首被pattern所匹配到的字符串,以substi替换之;
${var/%pattern/substi}:查找var所表示的字符串中,行尾被pattern所匹配到的字符串,以substi替换之;
查找并删除:
${var/pattern}:查找var所表示的字符串中,删除第一次被pattern所匹配到的字符串
${var//pattern}:查找var所表示的字符串中,删除所有被pattern所匹配到的字符串
${var/#pattern}:查找var所表示的字符串中,删除行首被pattern所匹配到的字符串,
${var/%pattern}:查找var所表示的字符串中,删除行尾被pattern所匹配到的字符串,
字符大小写转换:
${var^^}:把var中的所有小写字母转换为大写;
${var,,}:把var中的所有大写字母转换为小写;
变量赋值:
${var:-value}:如果var为空或未设置,那么返回value;否则,则返回var的值;
${var:=value}:如果var为空或未设置,那么返回value,并将value赋值给var;否则,则返回var的值;
${var:+value}:如果var不空,则返回value;
${var:?error_info}:如果var为空或未设置,那么返回error_info;否则,则返回var的值;
为脚本程序使用配置文件:步骤如下
(1) 定义文本文件,每行定义“name=value”
(2) 在脚本中source此文件即可
命令:
mktemp命令:创建临时文件或临时目录
mktemp [OPTION]... [TEMPLATE]
TEMPLATE使用filename.XXX,其中XXX至少要出现三个;
-d: 创建临时目录;
--tmpdir=/PATH/TO/SOMEDIR:指明临时文件或目录位置;
例如 mktemp /tmp/somefile.XXXX
install命令:
install [OPTION]... [-T] SOURCE DEST 单个复制文件
install [OPTION]... SOURCE... DIRECTORY 复制多个文件到目录中
install [OPTION]... -t DIRECTORY SOURCE...
install [OPTION]... -d DIRECTORY... 创建空目录
选项:
-m MODE
-o OWNER
-g GROUP
-D
例如 install -m 700 -d workspace 创建空目录workspace,并且指明权限为700
install -D /usr/sbin/ss /mnt/sysroot/usr/sbin/ss
练习:写一个脚本
(1) 提示用户输入一个可执行命令名称;
(2) 获取此命令所依赖到的所有库文件列表;
(3) 复制命令至某目标目录(例如/mnt/sysroot)下的对应路径下;
/bin/bash ==> /mnt/sysroot/bin/bash
/usr/bin/passwd ==> /mnt/sysroot/usr/bin/passwd
(4) 复制此命令依赖到的所有库文件至目标目录下的对应路径下:
/lib64/ld-linux-x86-64.so.2 ==> /mnt/sysroot/lib64/ld-linux-x86-64.so.2
进一步地:每次复制完成一个命令后,不要退出,而是提示用户键入新的要复制的命令,并重复完成上述功能;直到用户输入quit退出;
#!/bin/bash
#
if [ $# -ne 2 ] ; then
echo "usage: `basename $0` COMMAND DIRECTORY" # $1是命令,$2是一個目錄
exit 1
fi
if [ ! -e $1 ];then
echo "$1 is not a exists file"
exit 2
fi
if [ ! -d $2 ];then
echo "$2 is not a exists directory"
exit 3
fi
declare -a dep_files #dep_files 表示数组
declare -a dep_files_need
declare -i i=0
dep_files=(`ldd $1`)
#echo ${dep_files[*]}
for item in ${dep_files[*]};do
if echo $item | grep -E "^/.*so\.[0-9]$" &> /dev/null ;then
dep_files_need[i]=$item
let i+=1
fi
# echo $item
done
echo ${dep_files_need[*]}
if [ ! -e $2$1 ];then
install -D $1 $2$1
fi
for item in ${dep_files_need[*]};do
if [ ! -e $2$item ];then
install -D $item $2$item
fi
done
评论
发表评论