高性能Linux服务器运维实战(系统基础运维)

第1章 Linux基础命令的使用

1.1 Linux命令行与shell

1.1.1命令是Linux的精髓

  • X-window运行在命令行下的一个应用程序

1.1.2用户和操作系统内核之间通信的桥梁shell

  • Bourne shell(sh) 、Bourne again shell(bash) C shell(csh)、Tenex C shell(tcsh)、Korn shell(ksh)
  • 少数linux发行版#!/bin/sh指向dash
    dash(符合posix,unix系统,无交互)
  • 一种命令解释程序;一种功能强大的解释型程序设计语言
  • shell自身解释执行的命令称为内置命令cd,pwd,exit,echo都是bash内置命令;可执行文件/bin/ls…,被调用时系统装入内存执行(根据用户给出路径或者环境变量找到可执行文件)
  • shell命令提示符:#表示系统超级用户,*普通用户

1.1.3shell命令行的格式以及如何使用

1、格式

  • command [-options] [arguments]
ls -al /etc
mv a.txt b.txt

2、;和\

ps -elf | head -1;ps -elf | sort -rn -k3 | head -10
cat > a.txt << EOF
abc 
efg 
hij
EOF
cp -i \
a.txt \
b.txt

1.1.4shell中常用通配符的使用

1、bash中常用通配符*,?,[ ]

  • *匹配任意一个或多个字符

  • ?匹配任意单一字符

  • [ ]匹配任意一个在方括号内的单字符
    [123456],[1-6]

2、通配符组合使用

  • [0-9]?.conf,匹配数字开头后跟一个字符conf文件
  • [xyz]*.txt,匹配x或y或z开头的txt文件

1.1.5shell输入输出和错误重定向

1、输入重定向<,<<

#计算行数,单词数,字符数
wc < /etc/passwd
wc << aa 
abc
efg
aa

通知shell当前命令标准输入来自一对分隔符之间

2、输出重定向>,>>

ps -ef > ps.txt
#合并文件
cat file1 file2 file3 > file
  • >不存在创建,存在覆盖。>>不存在创建,存在后面追加

3、错误重定向2>2>>

#正常屏幕上看到解压过程,如果包损坏错误信息输出到error.txt
tar zxvf text.tar.gz 2>error.txt

1.1.6shell中管道如何使用

ls -al /etc | more
ps -ef | grep httpd | wc -l

1.1.7shell中3种引用字符如何使用

#转义字符\放在特殊字符前,忽略特殊字符的原有含义
mv abc\?\* abc
#单引号' '字符串所有字符的特殊含义将被忽略
mv 'C:\backup' backup
#双引号" "字符串大部分特殊字符当作普通字符处理,但$、\、`仍保留特殊含义
str="the \$shell current shell is $shell"
echo $str

1.2 基础运维类命令

1.2.1如何对文件打包、压缩与解压缩

tar、gzip、gunzip、bzip2、bunzip2

1、文档归档并压缩解压命令tar

  • 主选项 -c,-x,-t,-r,-u
  • 附加选项 -z,-j,-v,-f,-p,-w,-Z,-N "yyyy/mm/dd", -exclude file
tar -cvf /opt/etc.tar /etc
tar -zcvpf /opt/etc.tar.gz /etc
tar -jcvf /opt/etc.tar.bz2 /etc
tar -ztvf /opt/etc.tar.gz
tar -zxvf /opt/etc.tar.gz etc/inittab
tar -jtvf /opt/etc.tar.bz2
#第一f后面的-将创建的文件输出到标准输出上
#第二f后面的-从标准输入中读取数据
tar -zcvf - /etc | tar -zxvf -
#自动备份脚本
#!/bin/sh                                                                              
#变量                                                                                      
days=7                                #本地备份文件保留天数                                                       
user=laaos                            # 本地用户名                                                   
remoteuser=tsmem                      # 远程备份机用户                                            
datetime=`date +%Y_%m_%d`             #备份日期
baksrcdir=/db/mysql/data              #需要备份的文件
bakupdir=/data/backupdata             #本地备份文件存放目录         
bakdata=${user}_${datetime}.tar.gz    #备份文件名称
baklog=${user}_${datetime}.log        #备份日志 
remoteIP=192.168.23.130               #远程备份机地址
remotePath=/backupdata/dbdata         #远程备份文件存放路径 

#备份
#进入备份文件将存放目录
cd ${bakupdir}
#判断是否存在以用户命名的文件夹,如果不存在创建
if [ ! -d "${user}" ];then
 mkdir "${user}"
fi
#进入以用户命名的文件夹
cd ${user}
#向日志文件写入日期和具体时间
echo "backup start at ${datetime} `date`" > ${baklog}
echo "-----------------------" >> ${baklog}
#备份数据和日志
tar -zcvf ${bakdata} ${baksrcdir} ${baklog}
#删除本地日志文件
find ${bakupdir}/${user} -type f -name "*.log" -exec rm {} \;
#删除本地超过保存天数的备份文件
find ${bakupdir}/${user} -type f -name "*.tar.gz" -mtime +$days -exec rm {} \;
#备份到远程
rsync -avzPL -e "ssh -i /home/laaos/.ssh/id_rsa" ${bakupdir}/${user}/${bakdata} ${remoteuser}@${remoteIP}:${remotePath}

#本地机器和远程备份机的无密码登陆操作
#ssh-keygen参数说明
#-b bits 指定要创建的秘钥中的位数,默认 2048 位。值越大,密码越复杂
#-C comment 注释,在 id_rsa.pub 中末尾
#-t rsa/dsa等 指定要创建的秘钥类型,默认为 RSA
#-f filename 指定公私钥的名称,会在 $HOME/.ssh 目录下生产私钥 filename 和公钥 filename.pub
#-N password 指定使用秘钥的密码,使得多人使用同一台机器时更安全
#方式一
#本地机器操作操作
ssh-keygen -t rsa
scp /usr/rsync_id_rsa.pub [email protected]:/home/remoteuser/.ssh
#远程备份机操作
cat rsync_id_dsa.pub >> authorized_keys
chown remoteuser:remoteuser authorized_keys
方式二
# 生成公私钥,默认文件为 ~/.ssh/id_rsa
ssh-keygen -t rsa -b 4096 -C "[email protected]"
# 发送公钥的两种方式(等价)
ssh-copy-id -i ~/.ssh/id_rsa.pub user@host
ssh user@host 'mkdir -p .ssh && cat >> .ssh/authorized_keys' < ~/.ssh/id_rsa.pub
#管理秘钥
#ssh-agent 和 ssh-add 是安全外壳(SSH)协议套件的标准组件,用于管理私钥。
#一般情况下我们使用不带密码的 id_rsa 作为我们的默认私钥,此时是没必要启动 ssh-agent 的。
#当我们碰到以下两种情况则需要它:
#1,使用不同的秘钥连接到不同的主机时,需要手动指定对应的秘钥。(ssh-agent 帮我们选择对应的秘钥进行认证)
#2,当私钥设置了密码,而我们又需要频繁的使用私钥进行认证。(ssh-agent 帮我们免去重复输入密码)

#代理常用命令
# 启动代理
eval `ssh-agent`
# 关闭代理
ssh-agent -k
# 在 ~/.bashrc 中加入以下来实现登陆自动启动 ssh-agent,退出自动 kill 掉程序
eval $(ssh-agent -s) > /dev/null
trap 'test -n "$SSH_AGENT_PID" && eval `/usr/bin/ssh-agent -k` > /dev/null' 0

# 查看代理中的私钥
ssh-add -l
# 查看代理中私钥对应的公钥
ssh-add -L
# 移除指定的私钥
ssh-add -d /path/of/key/key_name
# 移除所有的私钥
ssh-add -D
#保证/etc/ssh/sshd_config文件中“AuthorizedKeysFile      .ssh/authorized_keys”语句未被注释
#不希望输入IP,保证/etc/hosts文件存在“IP HOST”
#ssh-keygen -t rsa生成秘钥(id_rsa和id_rsa.pub)存在~/.ssh文件夹中
#将公钥写入证书
cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys
ssh root@node02 cat /root/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys
#将证书拷贝到其他机器
scp ~/.ssh/authorized_keys root@node02:/root/.ssh/authorized_keys
#一台本地主机需要维护多台远程服务器的话,如果生成多个公钥密钥对的话本地文件肯定重名,怎么办呢!?
#其实公钥之所谓公钥,就是公开的密钥,只需要在本地生成一对公钥私钥然后将公钥分别放在多台远程服务器上就行了!
正确做法

ssh UserB@ServerB  'echo "hello world" > index'
  没错,只是单纯的用引号将命令括起来就行了,这样会被当做位置参数传递给ssh,然后就能成功在远程机上运行了

#!/bin/bash
#多进程对多个机器同时发指令

#注意下面的用户和ip是一一对应的,顺序不要搞错,额否则不能登录
#user1登录server1
server=(
    "192.168.1.1"
    "192.168.1.2"
    "192.168.1.3"
    "192.168.1.4"
)
user=(
    "test1"
    "test2"
    "test3"
    "test4"
)

#服务器和用户账号对应关系
tot_s=${#server[*]}
tot_u=${#user[*]}

if [ $tot_s -ne $tot_u ];then
    echo "服务器和用户账号数量不对应,请检查server列表和user列表"
    exit
fi

i=0
while [ $i -lt $tot_u ];do
    (ssh ${user[$i]}@${server[$i]} "command1;command2" & )  2>> ~/Desktop/log.txt
    #注意一定要在最后面加&符号,否则就是串行执行,不能体现并行。
    #将错误重定向到日志文件中

    if [ $? -ne 0 ];then
        echo "${user[$i]}@${server[$i]}执行过程中出现异常"
    fi

    #注意迭代器别忘了自增
    i=$[ $i + 1 ]
done

2、文件压缩解压命令gzip/gunzip
-d,-r,-t,-v,-l,-num
gzip -d等价gunzip

3、文件压缩解压命令bzip2/bunzip2

  • -d,-v,-t,-k保留原始文件,-f覆盖同名文件-压缩级别

1.2.2如何快速查找、搜索文件

1、强大的文件查找命令find
find pathname -options -print -exec command {} \;

  • -name,-lname,-path,-group,-user
  • -gid,-uid,-size,-mtime +-,-type bcfldps,
  • -depth,-prune,-empty,
#\ 表示不由shell解释为特殊字符,而由find命令区解释其意义
find / \( -path  /var/log -o -path /usr/bin \) -prune -o -name "a.txt" -print 

2、给其他命令传递参数的过滤器命令xargs

touch {1..9}.txt
  • 标准输入是一个缓冲区,命令设计一般先从命令行获取参数,再从标准输入中读取
  • kill,rm不会默认从标准输入中读取数据
  • xargs将管道传来的数据当作命令行参数
  • xargs -i接受传递的分批结果{}作为替换符号放到需要参数的位置可实现对个传递,
    -t打印命令执行过程才正式执行,
    -p交互式询问,-d @指定分隔符,
    -n 3一次性传递3个参数,
find . -name "*.txt" | xargs -i -t rm -rf {}
#文件名有空格的删除
#更广泛
find -name "* *.log" -prnt0 | xargs -0 rm -rf
#更通用型非find命令(如ls)也行
find -name "* *.log" | xargs -i rm -rf "{}"
ls | grep ". ..log" | xargs -i -rm -rf "{}"

1.2.3如何对文件进行连接、合并、排序、去重

#文件连接命令join
join -t ':' -1 3 file1 -2 3 file2

#合并文件命令paste
cat /etc/group | paste /etc/passwd /etc/shadow - | head -n 3

#文件排序命令sort
cat /etc/passwd | sort -t ':' -k3 -rn | head -n 10
#head 等价于 head -10

#检查并删除文件重复行命令uniq
sort file | uniq -d -c

1.3 系统运维监控类命令

1.3.1查询当前整个系统每个进程的线程数

for pid in $(ps -ef | grep -v grep | grep java | awk '{print $2}')
 do 
  echo ${pid} >/tmp/a.txt
  cat /proc/${pid}/status | grep Threads >/tmp/b.txt
  paste /tmp/a.txt /tmp/b.txt
 done | sort -k3 -rn

1.3.2如何检测系统中的僵尸进程并将其kill

ps -e -o stat,ppid,pid,cmd | grep -e '^ [Zz]' | awk '{print $2}' | xargs -i kill -9

1.3.3查看当前占用CPU或内存最多的几个进程

#获取当前系统占用CPU最高的前10个进程
ps aux | head -1;ps aux | sort -rn -k3 | head -10
#获取当前系统占用内存最高的前10个进程
ps aux | head -1;ps aux | sort -rn -k4 | head -10

1.4 网络故障排查类命令

1.4.1命令行下载工具wget命令

#使用wget下载单个文件并使用--limit-rate参数进行限速下载
wget --limit-rate=1M http://mirror.163.com/centos/7.6.1.1810/isos/x86_64/Centos-7-x86_64-DVD-1810.iso

#使用wget -c断点续传
wget -c http://mirror.163.com/centos/7.6.1.1810/isos/x86_64/Centos-7-x86_64-DVD-1810.iso
#测试服务器是否支持断点续传
#执行结果出现Accept-Ranges:bytes说明服务器支持短点续传下载
wget -S http://mirrors.163.com 2>&1 | grep "Accept-Ranges"

#使用wget下载文件以不同的文件名保存(一般以最后一个/后面的字符命名)-O指定一个文件名
wget -O php-7.3.2.tar.bz2 http://cn2.php.net/get/php-7.3.2.tar.bz2/from/this/mirror

1.4.2强大的http命令行工具curl(Command URL)

#通过curl显示网站的header信息
curl -I http://www.baidu.com

#显示网站的http状态代码,-w输出一些定义的元数据
#http_connect,time_total,time_connect,time_appconnect,time_redirect,
#size_download,size_upload,content_type,ssl_verify_result
curl -s -o /dev/null -w %{http_code} "\n" http://www.baidu.com

#使用curl实现URL地址重定向,-L自动地址重定向
curl -L -I http://www.baidu.com

#抓去网页内容并保存到本地
curl -O http://www.baidu.com/default.htm
curl -o test.htm http://www.baidu.com/default.htm

通过curl下载文件并开启断点续传,宽带限速,-C实现断点续传,-C-实现自动续传
curl --limit-rate 2M -C- -O http://www.baidu.com/mirror.iso

1.4.3linux系统之间文件传输工具scp命令

#远程复制到本地
scp RemoteUser@IP:RemoteAbsolutePath/file LocalPath

#本地复制到远程
#默认端口22,-P指定端口;     cp -r与scp -r含义一致,-l 1000限速单位Kbit/s
scp -r -P 1022 -l 10000 LocalPath/file RemoteUser@IP:RemoteAbsolutePath 

1.4.4动态路由跟踪及网络排查工具mtr

#第一部分路由信息Host
#第二部分丢包率Loss%(丢包可能是ICMP保护机制),发送数据包数量`Snt`
#第三部分Last,Avg,Best,Wrst,StDev最后一次,平均,最小,最大,标准偏差包延迟
yum install mtr
mtr 192.168.23.13

第2章 shell实战编程与应用案例

2.1 正则表达式与变量

2.1.1正则表达式的组成与应用

1、什么是正则表达式(Regular Expression,RE)

  • 一系列特殊字符和普通字符组成的字符串,每个特殊字符称为元字符,主要功能实现文本查询和字符串操作。

2、正则表达式组成由一下一项或多项

  • 一个字符集(普通字符)——正则表达式最简单形式
  • 锚(^和$)——正则表达式所匹配文本在文本行所处位置
  • 修饰符(*星号、<>[]{}括号、\反斜杠)——扩大或缩小正则表达式匹配文本的范围
  • 正则表达式常用符号及含义
    *匹配前面一个普通字符的0次或多次重复
    .匹配任意一个字符
    ^匹配行首或后面字符的非
    $匹配行尾
    ^$匹配空白行
    []匹配字符集合中某一个字符
    \转义符,屏蔽一个元字符的特殊意义
    \<\>精确匹配符号
    \{n\}匹配前面字符出n次
    \{n,\}匹配前面字符至少出n次
    \{n,m\}匹配前面字符出n次m次之间
    [xyz],[c-n],[B-Pk-y],[a-z0-9],[\^b-d],[Yy][Ee][Ss]
    [a-z]\{5\}匹配5个小写英文字母

2.1.2shell中的变量与应用

1、变量的定义与分类

  • 用户自定义变量——用户自定义,修改和使用
  • shell环境变量PATH——设置用户shell工作环境,少数用户修改其值
  • 位置参数变量(Positional Parameters)——命令行给程序传递执行参数,shift命令实现位置参数的迁移
  • 内部参数变量(Special Parameters)——bash预定义的特殊变量,用户不能修改其值

2、变量的赋值

  • $变量替换符号,variable变量名,$variable变量值
#变量赋值 
variable=value
variable=`command argument`
  • 变量名只能包括数字、字母、下划线,数字不能作为开头

3、变量的声明和使用

  • shell变量是弱变量不用声明类型
  • 变量声明和赋值variable=value(等号两边不能有空格)
#变量引用
#一个字符的变量名
$variable
#多个字符变量名
${variable}

4、变量的清除和只读

  • 变量不再使用,清除变量unset variable
  • 变量设置为只读,用户将不能对此变量重新赋值和清除
variable=value
readonly variable

5、内部参数变量

  • 内部参数变量及含义
    $@表示传递给脚本或函数的所有参数。被双引号"“包含时,所有参数仍然分开$1、$2输出。
    $*表示传递给脚本或函数的所有参数。当被双引号”"包含时,所有参数作为一个整体$1$2输出。
    $0命令行上输入的shell程序名
    $#命令行上参数的个数

  • 进程相关内部参数
    $?表示上一条命令执行后的返回结果
    $$表示当前进程号
    $!显示运行在后台的最后一个作业的pid
    $_表示之前执行的命令或脚本的最后一个参数

  • 内部域分隔符IFS(Interal Field Seperator)默认值值为空白(空格、Tab和新行)

#IFS转化八进制
echo "$IFS" | od -b
#040是空格,011是Tab,012是换行符

“$*“会根据IFS不同来组合值,$@、”$@”、$*会将值用空格来组合值,推荐使用$@

6、位置参数变量

  • 一种特殊的shell变量,用于命令行向shell脚本传递参数
  • $1表示第1个参数,${10}表示第10个参数(10开始参数号需要用大括号括起来)

7、退出/返回状态(0:成功;1-255:失败)

  • 常见退出返回状态码含义
    0执行正确或成功
    1通用错误或执行失败
    124网络不通
    126命令或脚本没有执行权限
    127命令没找到

8、命令替换(抽取一个命令的输出)

#命令替换两种形式
`linux_comman`
$(linux_command)

9、read命令(接受键盘输入内容为变量赋值)

#read例子
#读取变量给variable
read variable
#同事读取多个变量
read x y
#自动从键盘读取输入内容,并复制给REPLY变量
read
#自动从键盘读取输入内容,并复制给REPLY变量,并给出输入提示
read -p "please input:" 
  • 结合不同引号为变量赋值
    双引号" "允许通过$引用其他变量
    单引号’ '禁止引用其他变量
    反撇号``将命令执行结果输出给变量

2.1.3变量测试、截取与替换

1、变量测试的用法(shell支持变量测试和默认赋值)

#变量测试几种用法和含义
#var存在且非空,值为$var;var未定义或为空,测试值为word,var值不变。
${var:-word}
#var存在且非空,值为$var;var未定义或为空,测试值为word,var赋值word。
${var:=word}
#var存在且非空,值为$var;var未定义或为空,输出信息word,中止脚本。
${var:?word}
#var存在且非空,值为word;否则返回空值,var值不变。
${var:+word}

2、字符串长度和截取(awk和sed文本字符串过滤、筛选、替换,shell也支持此功能)

#字符串长度与截取的用法与含义
#返回字符串变量var长度
${#var}
#返回${var}中从m个字符之后的所有部分
${var:m}
#返回${var}中从m个字符之后开始,长度为len的部分
${var:m:len}
#删除${var}中开头部分与pattern匹配的部分
${var#pattern}
#删除\${var}中结尾部分与pattern匹配的部分
${var%pattern}
  • 字符串替换用法
#用new替换${var}中第一次出现的old
${var/old/new}
#用new替换${var}中所有的old(全局替换)
${var//old/new}
#用new替换${var}中开头部分与old匹配的部分
${var/#old/new}
#用new替换${var}中结尾部分与old匹配的部分
${var/%old/new}

3、变量的间接引用

str="hello world"
str1=str
echo ${ ! str1 }
eval echo \$$str1

4、同时输出多行信息

echo "
line
line0
lne1
"
#END为任意字符串
cat << END
line
line0
lne1
END

2.2 运算符、测试操作符以及if语句

2.2.1算数运算符(+、-、*、/、%、**)

1、算数运算扩展(运算数只能是整数)

  • 算数表达式求值替换成所求得的值
$[expression]
$((expression))
((num=2+3**2-1001%5));echo $num
num=$((2+3**2-1001%5));echo $num
echo $((2+3**2-1001%5))
  • $(( ))中的变量可以用$也可以不用$
echo $((a+b*c))
echo $(( $a + $b * $c ))
#同理$[???]
  • 单纯用(( ))也可重定义变量值
((a++)),((a--))

2、算术运算指令expr

  • (数值运算、数值或字符串比较、字符串匹配、字符串提取、字符串长度计算等功能;
  • 判断变量或参数是否为整数、是否为空、是否为零等)
  • 表达式中参数和操作符必须以空格分开,乘法符号和括号必须被转义
expr 5 % 3
expr 5 \* 3
expr \( 2 + 5 \) \* 2 - 6

3、算术运算指令let

  • let是bash的内部命令,从左到右顺序给每一个参数进行算术运算;
  • 最后一个参数求值结果为真返回退出码0,否则返回1
  • let命令功能与算术运算扩展基本相同,默认情况下任何操作符两边不能留空格
  • 所有算术表达式连接在一起,使用空格时需要用双引号将表达式括起来
  • 赋值符号和运算符两边不留空格,字符串赋值给整型变量时变量值为0,变量值是字符串进行算术运算时设为0
#let进行算术运算时最好加双引号
let "num=4 + 1"

4、自增自减运算符

  • 前置自增(++variable)、前置自减(--variable)首先改变变量,再将变量交给表达式使用
  • 后置自增(variable++)、后置自减(variable--)表达式使用过后再改变变量的值

2.2.2条件测试和条件测试操作符

1、条件测试

  • (某个特定条件是否满足,选择执行相应任务;
  • bash允许测试两种类型的条件:命令成功或失败、表达式为真或为假;
  • 0表示成功和真,非0表示失败和假)
查找当前用户是否存在
grep $USER /etc/passwd
#结果为0,表示用户存在
echo $?

2、test与条件测试语句
* test命令在shell中主要用于条件测试,返回0值为真,返回大于0值为假;

  • test命令支持测试的范围包括字符串比较、算术比较、文件是否存在、文件属性和类型判断等

  • shell中条件测试语法格式有三种:
    test expression完全等价[expression]基本等价于[[expression]]bash2.x版本以上&支持更多表达式:&&、||、!、()

  • 单双中括号内左右两边必须有空格

  • 整数进行关系运算,还可用(( ))。(( ))进行整数测试,其中变量前缀$可有可无

  • 条件测试表达式中常见操作符
    字符串测试操作符、整数比较操作符、逻辑运算符、文件测试操作符

#test命令测试表达式的值
x=8; y=12; test $x -gt $y; echo $?  #值为1假
x=8; y=12; test $x -lt $y; echo $?  #值为0真
x=8; y=12; [ $x -gt $y ]; echo $?   #值为1假
x=8; y=12; [ $x -lt $y ]; echo $?   #值为0真

3、方括号测试表达式

  • [[ ]]基本等价于[ ],功能写法更简洁,且提供正则表达式[[ ]]功能可认为是test和expr命令的相加
  • [[ conditional_expression ]]bash2.x版本以上,可使用通配符进行模式匹配
name=Tom; [ $name = [Tt]?? ]; echo $?    #值为1假,[ ]不支持通配符
name=Tom; [[ $name = [Tt]?? ]]; echo $?  #值为0真,[[ ]]支持通配符

4、字符串测试操作符

  • 字符串测试操作符作用:比较两个字符串是否相同、字符串长度是否为零、字符串是否为NULL
#字符串测试操作符及含义(单双中括号两边必须留空格)
#如果字符串str长度为0,返回真
[ -z str ]
#如果字符串str长度不为0,返回真
[ -n str ]
#如果字符串str不为空,返回真
[ str ]
#测试字符串str是否与字符串str0相等,可使用==代替=
[ str = str0 ]
#测试字符串str是否与字符串str0不相等,可使用!==代替!=
[ str != str0 ]

#两个字符串相同返回真
[[ str == str0 ]]
#两个字符串不相同返回真
[[ str != str0 ]]
#str0是str子串返回真
[[ str =~ str0 ]]
#str>str0返回真
[[ str > str0 ]]
#str
[[ str < str0 ]]
#字符串中有空格,进行字符串长度是否为0判断时,将变量加上双引号,命令正常执行。
name="Tom sql"; [ -z "$name" ]; echo $?
#总结:字符串或字符串变量比较,都加双引号;字符串或字符串变量比较,比较符号两端都有空格;
#=比较两个字符串是否相等,与==等价,最好办法
[ "${s}" = "${b}" ]
#检查字符串是否为空
[ "$name" = "" ],[ -z "$name" ],[ ! "$name" ],[ "X${name}" = "X" ]
#检查字符串是否为非空值
[ "$name" != "" ],[ -n "$name" ],[ "$name" ],[ "X${name}" != "X" ]

5、逻辑测试操作符

  • 逻辑非、与、或
[ expr -a expr0 ] #逻辑与,都为真时,结果为真
[ expr -o expr0 ] #逻辑或,有一个为真时,结果为真
[ ! expr ]       #逻辑非
#例子(不能在中括号中随意添加小括号)
x=1; name=tom; [ $x -eq 1 -a -n $name ]; echo $?
#匹配模式的逻辑测试操作符及含义(只能在双中括号中,不能在单中括号中)
[[ pattern && pattern0 ]]         #逻辑与
[[ pattern || pattern0 ]]         #逻辑或
[[ ! pattern ]]                    #逻辑非
#匹配模式的逻辑测试表达式支持通配符
 x=1; name=Tom; [[ $x -eq 1 && $name = To? ]]; echo $?

6、整数测试操作符(整数测试即比较大小)

#整数测试操作符与含义
[ int -eq int0 ]#int等于int0
[ int -nq int0 ]#int不等于int0
[ int -gt int0 ]#int大于int0
[ int -ge int0 ]#int大于或等于int0
[ int -lt int0 ]#int小于int0
[ int -le int0 ]#int小于或等于int0
[[ int -eq int0 ]]#int等于int0,返回真
[[ int -nq int0 ]]#int不等于int0,返回真
[[ int -gt int0 ]]#int大于int0,返回真
[[ int -ge int0 ]]#int大于或等于int0,返回真
[[ int -lt int0 ]]#int小于int0,返回真
[[ int -le int0 ]]#int小于或等于int0,返回真
#整数测试操作符中,单双中括号对应操作符两边必须留空格;比较的只能是整数。

#双小括号的整数测试操作符与含义,双小括号操作符两边的空格可以省略
((int == int0))int等于int0,返回真
((int != int0))int不等于int0,返回真
((int > int0))int大于int0,返回真
((int >= int0))int大于或等于int0,返回真
((int < int0))int小于int0,返回真
((int <= int0))int小于或等于int0,返回真
#==,!=,<,>操作符也可用在单双中括号中,只不过<和>符号在[ ]中使用需要转义

7、文件测试操作符(测试文件是否存在、文件属性、访问权限等场景)

#文件测试操作符与含义
[ -f fname ] #fname存在且是普通文件时,返回真(即返回0)
[ -L fname ] #fname存在且是链接文件时,返回真
[ -d fname ] #fname存在且是一个目录时,返回真
[ -e fname ] #fname(文件或目录)存在时,返回真
[ -s fname ] #fname存在且大小大于0时,返回真
[ -r fname ] #fname(文件或目录)存在且可读时 ,返回真
[ -w fname ] #fname(文件或目录)存在且可写时,返回真
[ -x fname ] #fname(文件或目录)存在且可执行时,返回真

8、条件测试举例

#值为0,命令中&&并非逻辑运算符,而是命令聚合符号
x=6; name=iivey; (( $x == 6 )) && [[ $name = iive? ]]; echo $?
#值为1,字符串变量作比较,变量最好用双引号括起,方括号内前后留空格,[ ]内不能使用通配符
name=tom; name0=ivvey; [ "$name" = "$name0" ]; echo $?
#结果为假,整数测试,双小括号中可以加上变量前缀\$,也可以省略\$,对执行结果不影响
n=5; m=7; ((n>m)); echo $?和n=5; m=7; (($n>$m)); echo $?
#结果为假,整数测试
n=5; m=7; [[ $n>$m ]]; echo $? 
#结果为真,去掉$后变成了字符串测试大小,这里比较n和m对应的ASCII码大小
n=5; m=7; [[ n>m ]]; echo $?
#结果为T,…&&…||…第一句为真,输出第二句;第一句为假,输出第三句
a=linux; b=unix; [ $a != $b ] && echo T || echo F

2.2.3if/else判断结构

1、简单if结构

#简单
if expression
 then
  command
fi
#或者
if expression; then
  command
fi

2、if/else结构

#普通
if expression
 then
  command
 else
  command
fi
#嵌套
if expression
 then
  if expression
   then  
    command
   else 
    command
  fi
 else
  command
  exit
fi

3、if语句执行流程

  • 单分支if-then-fi
  • 双分支if-then-else-fi

4、if/elif/else结构

  • if-then-(elif-then)-…else-fi,
  • elif expression; then

5、使用if/else判断注意事项

  • if语句必须以if开头,以fi结尾
  • elif可以任意多个(0个或多个)
  • else最多只能有1个(0个或一个)
  • command为可执行语句块,如果为空,需要使用shell提供的空命令:,即冒号。
  • expr通常为条件测试表达式,可以是多个命令,以最后一个命令退出状态为条件值
  • if语句可以嵌套使用

2.3 case选择、for循环与结构化命令

2.3.1case选择语法与应用举例

  • case…esac与其他语言switch…case类似,是一种多分支选择结构:case语句匹配一个值或一个模式,如果匹配成功则执行相匹配的命令

1、语法结构

case expr in
 pattern)
  commands
  ;;
 pattern0)
  commands0
  ;;
 …
 *)
  commands1
  ;;
esac

2、case语句的几点说明

  • 表达式expr选择语句按顺序匹配每个模式,一旦有模式匹配成功,则执行该模式后面的所有命令,然后退出case
  • 如果expr没有找到匹配模式,则默认执行*)后面的命令块(类似if中的else)可以不出现
  • 匹配模式pattern中可以含有通配符和|
  • 每个命令块的最后必须有一个双分号,可以独占一行,或放在最后一个命令的后面

2.3.2for循环和结构化命令

1、列表for循环

#列表for循环语法结构
for variable in list
 do
  commands
 done
  • list列表中带有空格的列表项,必须用双引号括起来作为一个整体
  • list列表不是固定的字符,而是命令组合。$x和eval $x的区别:$x打印命令,eval $x执行命令

2、不带列表for循环

  • 不带列表的for循环执行是由用户指定参数和参数的个数
  • do和done之间的命令称为循环体,shell自动将命令行输入的所有参数依次组织成列表,每次将一个参数显示给用户,直到命令行中所有参数都显示给用户
#不带列表的for循环的基本格式
for variable
 do
  command
  command
 done
#或者
for variable; do
  command
  command
 done
#不带列表的for循环其实是使用了位置参数$@来传递for中的list列表,for循环省略了in $@关键字

3、for循环举例

#使用文件名或目录名列表作为list,*表示当前目录下的文件和目录
#! /bin/bash
for fname in *; do
  fn=$(echo $fname | tr A-Z a-z)
  if [[ $fname != $fn ]]; then mv $fname $fn; fi
 done

#使用命令的执行结果作为list的for循环,awk -F '{print $1}'被反单引号包括
#! /bin/bash

i=1
for username in awk -F '{ print $1}' /etc/passwd
 do
  echo "Username $((i++)) : $username"
 done

for suffix in $(seq 10)
 do
  echo "192.168.23.${suffix}"
 done

#使用命令替换符的结果作为list
#! /bin/bash
for host in $(cat /etc/hosts)
 do
  if ping -c 1 -w 2 $host &>/dev/null
   then
    echo "Host ($host) is active."
   else
    echo "Host($host) is Down."
  fi
 done

#使用数值范围作为list,{1..10}和$(seq 10)表示分别读取一到十中的数,{1..10..2}表示分别每隔两个步长读取一到十中的数
#! /bin/bash
mynet="192.168.0"
for num in {1..6}
 do
   echo "ip address is ${mynet}.$num"
 done

for num in {1..10..2}
 do
   echo "Number: $num"
 done

#批量添加10个linux系统用户,stdin是接受后面的字符串作为密码,stdin表示非交互直接传入密码;
#passwd默认终端作为标准输入,加上- -stdin表示可以用任意文件作为标准输入,于是这里用管道作为标准输入;
#chage命令强制新用户第一次登陆时修改密码
#! /bin/bash
for x in {1..10}
 do
  useradd user${x}
  echo "Centos" | passwd --stdin user${x}
  chage -d 0 user${x}
done

4、break和continue

  • break强制退出当前循环,如果嵌套循环break命令后可跟一数字n,表示退出第n重循环(最里面的为第1重循环)
    break [n]

  • continue用于忽略本次循环的剩余部分,回到循环顶部,继续下一次循环,如果嵌套循环continue命令后也可跟一数字n,表示回到第n重循环的顶部
    continue [n]

#break例子
#! /bin/bash
i=1
for day in Mon Tue Wed Thu Fri
 do
  echo "Weekday $((i++)): $day"
  if [ $i -eq 3 ]; then
   break
  fi
 done

#continue例子
#! /bin/bash
i=1
for day in Mon Tue Wed Thu Fri Sat Sun
 do
  echo -n "Day $((i++)): $day"
  if [ $i -eq 7 -o $i -eq 8 ]; then
   echo "  (WEEKEND)"
   continue
  fi
  echo "  (weekday)"
 done

5、for循环(C语言)语法

  • 执行expr1;若expr2的值为真进入循环,否则退出for循环;执行循环体,之后执行expr3,然后判断expr2的值,为真继续循环;循环结束标志,返回循环顶部。
    * expr1和expr3为算术表达式,expr2为逻辑表达式,类C风格的for循环也被称为计次循环,一般用于循环次数已知的情况。
  • expr1为循环变量赋初始值,expr2是否循环的表达式,expr3改变循环变量的语句
for ((expr1;expr2;expr3))
 do
 commands
done
#例子批量新建linux系统用户
for (( n=1; n<=50; n++ ))
 do
  if ((n<10))
   then st="st0${n}"
   else st=st${n}
  fi
  useradd user${n}
  echo "Centos" | passwd --stdin user${n}
  chage -d 0 user${n}
 done

2.4 while循环、until循环以及select循环

2.4.1while循环结构

1、循环语句

  • 先执行expr,如果退出状态为0,就执行循环体,执行到done,回到循环顶部while再次检查expr退出状态,在以此类推,直到expr推出状态非0为止。
while expr
 do
  commands
 done

2、while循环语句执行流程

  • while循环语句也称前测试循环语句,为避免死循环,必须保证循环体中包含循环出口条件,即存在expr表达式的退出状态为非0的情况。

3、while循环例子

#最基本的while循环
#! /bin/bash
num=$((RANDOM%100))
while :
 do
  read -p "please guess my number [0-99]:" answer
  echo $num
  if [ $answer -lt $num ]
   then 
    echo "inputed number less than my number"
   elif [[ $answer -gt $num ]]; then 
    echo "inputed number greater than my number"
   elif ((answer=num)); then 
    echo "ok! congratulation:my number is $num"
  fi
 done
  • while从文件读取内容赋给指定变量
#! /bin/bash
while IFS=: read -r user enpass uid gid desc home shell
 do
  [ $uid -ge 500 ]  && echo "User $user $enpass ($uid) $gid $desc assigned "$home" home directory with $shell shell."
 done </etc/passwd
  • while配合read读取文件
#! /bin/bash
cat /etc/resolv.conf | while read line
                        do
                         echo $line
                        done
#! /bin/bash
file =/etc/resolv.conf
while IFS= read -r line
 do
   echo $line
 done < "$file"
  • while与管道配合使用
#! /bin/bash
DIR="."
find $DIR -type f | while read file; do
  echo $file
  if [[ "$file" = *[[ :space: ]]* ]]; then
   mv "$file" $(echo $file | tr ' ' '_')
  fi
 done
  • 计数器控制的while循环
#! /bin/bash
#counter计数器结构
counter=1
while expression
 do
  command
  ...
  let command to operate counter
 done

#counter计数器例子
counter=1
while [ $counter -lt 10 ]; do
  let "count+=1"
  echo $counter
 done

5、结束标记控制的while循环

#! /bin/bash
#结束标记控制结构
read variable
while [[ "$variable" != sentinel ]]
 do
  read variable
 done
#结构标记控制例子
#! /bin/bash
echo -e "please input values"
read variable
while [[ "$variable" != OK ]]; do
  read varible
  echo $variable
 done

6、标志控制的while循环

#标志控制结构
#! /bin/bash
signal=0
while (( signal != 1 ))
 do
  ...
  if expressioin
   then
    signal=1
  fi
  ...
 done

* 如果执行时没带参数OK就会一直循环
#! /bin/bash
signal=0
while (( signal != 1 ))
 do
  if [[ $@ = ok ]]; then
   signal=1
  fi
 done

2.4.2until循环语句以及应用举例

  • while循环在条件为真时执行,until循环则在循环条件为假时执行

1、

#until循环的语法
#! /bin/bash
until expr
 do
  commands
 done

2、until循环执行流程:条件不成立执行循环体
3、until循环举例

#循环将ping通IP,再ssh连接操作
#!/bin/bash
read -p "Enter IP Address:" ipadd
echo $ipadd
until ping -c 1 $ipadd $> dev/null
 do
  sleep 60
 done
ssh $ipadd

2.4.3exit和sleep的应用环境和方法

#exit用于推出脚本或当前进程
#sleep主要实现休眠指定的时间 sleep 1等价sleep 1s表示暂停1s
#sleep 1m表示暂停1分钟;sleep 1h表示暂停1小时
#! /bin/bash
username=$1
if [ $# -lt 1 ]; then
 echo "Usage: `basename $0`  []"
 exit 1
fi

if grep "^$username:" /etc/passwd >/dev/null; then :
 else
  echo "$username is not a user in the system."
  exit 2
fi

until who | grep "$username" > /dev/null; do
 echo "$username is not logged on."
 sleep 5
done

2.2.4select循环与菜单应用

while与case配合可以实现菜单循环;bash提供了select循环。

  • select循环主要用于创建菜单,按数字排列将菜单项显示在标准错误输出上,等待用户输入;菜单间的间隔符由环境变量IFS决定;引导用户输入的提示信息存放在环境变量PS3中;用户直接输入回车键将重新显示菜单(类似for循环);省略in list时等价于in “$*”,用户一旦输入某个数字则执行对应菜单中的命令,用户输入的内容保存在内置变量REPLY。
#! /bin/bash
PS3="What is your prferred scripting language "
select s in bash perl python ruby quit
 do 
  case $s in
   bash|perl|python|ruby) echo "You selected $s" ;;
   quit) exit ;;
   *) echo "You selected error,retry..." ;;
  esac

PS3= "What is your preferred OS?: "
IFS='|'
os="Linux|Gnu Hurd|FreeBSD|Mac OS X"
select s in $os
 do
  case $REPLY in
   1|2|3|4) echo "You selected $s" ;;
   *) exit ;;
  esac
 done

PS3="Select a program you want to execute: "
TOPLIST="telnet htop atop nettop jnettop iftop ftop iotop mytop innotop dnstopap achetop"
select prog in $TOPLIST quit
 do
  [[ $prog == quit ]] && exit
  rpm -q $prog > /dev/null && echo $prog || echo "$prog is not installed. "
 done

2.5函数以及函数的调用、参数的传递

2.5.1函数的概念

  • shell编程的函数和数学函数不一样
  • 函数是将程序里面多次调用的代码组合起来,成为函数体,并取一个名字称为函数名
alias F='/user/sbin/nginx'
F
ps -ef | grep nginx

2.5.2函数定义与语法

function fname{
 command
 [return]
}
functionname() {
 commands
}
  • 关键字function表示定义一个函数,可以省略;其后函数名,函数名后可以跟一个小括号‘()’;符号‘{’表示函数的入口,可在函数名那一行;‘}’表示函数体结束,两个大括号之间是函数体。
  • shell调用其他函数,函数中使用exit可以推出整个脚本,函数结束之后会返回调用的函数的部分继续执行,可以用break语句终端函数的执行

#! /bin/bash
function pws() {
 echo "i am the best"
}

function idnim() {
echo "to be better"
}
pws
idnim

2.5.3函数的调用、存储和显示

1、函数的调用

#! /bin/bash
function show() {
 echo "hello,you are calling the function "
}

echo "first time call the function"
show
echo "second time call the function"
show

#user defnie function
sql_bak() { echo "Running mysqldump tool ..."; }
sync_bak() { echo "Running rsync tool ..."; }
git_bak() { echo "Running gistore tool ..."; }
tar_bak() { echo "Running tar tool ..."; }

PS3="Please choose a backup tools: "
select s in mysqldump rsync gistore tar quit; do
 case $REPLY in
  1) sql_bak ;;
  2) sync_bak ;;
  3) git_bak ;;
  4) tar_bak ;;
  5) exit ;;
 esac
done

2、函数的存储

  • 函数和调用它的主程序保存在同一个文件中,此时函数的定义必须出现在函数调用之前;
  • 函数和调用它的主程序保存在不同的文件中,保存函数的文件必须先使用source命令执行,之后才能调用函数。

3、函数的显示

  • 显示当前shell可见的所有函数 declare -F
  • 显示当前shell可见的所有(指定)函数定义 declare -f function
  • 从shell内存中删除指定的函数unset -f
  • 将函数输出给shellexport -f

2.5.4函数与变量以及函数结果和返回值

  • 函数调用参数(Arguments),位置参数的形式为函数传递参数,$0函数名
  • $1,$2,${n},$*,$@表示其接受的参数,调用结束之后都将被重置为调用函数之前的值
  • 函数内使用local声明的变量是局部(Local)变量,局部变量的作用域是当前函数以及其调用的所有函数
  • 函数未使用local声明的变量是全局(Global)变量,即主程序和函数中的同名变量是一个变量(地址一致)

1、函数中参数的传递规则

#! /bin/bash
function show() {
echo "hello, youare calling the function $1"
}
echo "first time call the function "
show first
echo "second time call the function"
show second
#! /bin/bash
# 脚本内函数调用,脚本外通过位置参数传递值给函数
# 内部函数之间的互相调用
echo "====Print positional paramters in main :"
echo "$0: $*"
pp1(){
 echo 'f1--Print $* parameters in fun1 :'
 echo "$0:$*" 
}
pp2(){
 echo 'f2--Print $* parameters in fun1 :'
 echo "$0:$*"
 pp1 1rt 2nd 3th 4th 5th 6th 7th 8th 9th
 echo 'f2--Print $*parameters in fun1 :'
 echo "$0:$*"
}
pp1 1 2 3 4 5 6 7 8 9
echo "===Print positional parameters in main :"
echo "$0:$*"
pp2 I II III IV V VI VII VIII IX
#! /bin/bash
usage(){
 echo "List the MAX of the positive integers in command line. "
 echo "Usage: `basename $0` ..."
 exit
}
max(){
 [[ -z $1 || -z $2 ]] && usage
 largest=0
 for i; do ((i>largest)) && largest=$i; done
 max "$@"
 echo "The Largest of the numbers is $largest"
}

2、函数的结果和返回值

  • 函数最后一条命令执行结束,即函数执行结束;
  • 函数的返回值就是最后一条命令的退出码,其返回值被保存在系统变量$?;
  • 可使用return或exit显式地结束函数;
  • 函数关键字return可放到函数体的任意位置,shell执行return就停止往下执行,返回主程序的调用行。return返回值只能是0-256之间的一个整数
#! /bin/bash
function abc(){
 RESULT=`expr $1 \% 2`
 if [ $RESULT -eq 0 ]; then
  return 0
 else
  return 1
 fi
}
echo "Please enter a number who can devide by 2"
read N
abc $N
case $? in
	0)
	 echo "yes,it is"
	 ;;
	1)
	 echo "no,it is not"
	 ;;
esac
#! /bin/bash
# 比较两个数字的大小
# return只能返回0-256之间的整数,超过大小的数字比较会报错
max(){
 if [[ -z $2 ]] || [[ -z $2 ]]; then
  echo "Need two paramters to the function."; exit
 fi
 [ $1 -eq $2 ] && { echo "The two numbers are equal."; exit; } || (($1>$2)) && return $1 || return $2
}
read -p "Please input two integer numbers : " n1 n2
echo "n1=$n1,n2=$n2"
max $n1 $n2
return _val=$?
echo "The larger of the two numbers is $return_val."
# sh -x 脚本名称,查看脚本文件执行过程
#改进版本的数值比较
max(){
 if [[ -z $2 ]] || [[ -z $2 ]]; then
  echo "Need two paramters to the function."; exit
 fi
 largest=0
 [ $1 -eq $2 ] && { echo "The two numbers are equal."; exit; } || (($1>$2)) && largest=$1 || largest=$2
}
read -p "Please input two integer numbers : " n1 n2
echo "n1=$n1,n2=$n2"
max $n1 $n2
echo "The larger of the two numbers is ${largest}."

3、分离函数体执行函数的脚本文件

  • 函数定义过多,可把函数卸载一个文件中,写脚本需要调用函数时,就可直接调用文件中的函数名
#! /bin/bash
cat >>/etc/init.d/function<<EOF
function warrior(){
 echo "i am warrior"
 }
 EOF
 #代码导入/etc/init.d/function文件中,这个文件成为Linux系统内置的脚本函数库,按照下面方式调用
#分离函数执行体的功能,系统自带一些脚本中经常用到
if [ -f /etc/init.d/function ]
 then
  . /etc/init.d/function
fi
warrior

2.6 企业生产环境shell脚本案例汇总

2.6.1统计Linux进程数量信息脚本

#! /bin/bash
running=0
sleeping=0
stoped=0
zombie=0
for pid in /proc/[1-9]*
do
 procs=$[procs+1]
 stat=$(awk '{print $3}' $pid/stat)
  case $stat in
   R)
    running=$[running+1]
    ;;
   T)
    stoped=$[stoped+1]
    ;;
   S)
    sleeping=$[sleeping+1]
    ;;
   Z)
    zombie=$[zombie+1]
    ;;
  esac
done
echo "进程统计信息如下: "
echo "总进程数量为:$procs"
echo "Running进程数为:$running"
echo "Stoped进程数为:$stoped"
echo "Sleeping进程数为:$sleeping"
echo "Zombie进程数为:$zombie"
# 学习编写shell脚本的逻辑和思路,这个思路可以编写多个服务器状态的监测脚本

2.6.2监控主机的磁盘空间

#! /bin/bash
partition_lsit=(`df -h | awk 'NF>3&&NR>1{sub(/%/,"",$(NF-1));print $NF,$(NF-1)}'`)
critical=90
notificaton_email()
{
 emailuser='[email protected]'
 emailpasswd='password'
 emailsmtp='smtp.domain.com'
 sendto='[email protected]'
 title='Disk Space Alarm'
 /usr/local/sendEmail-v1.56/sendEmail -f $emailuser -t $sendto -s emailsmtp -u $title -xu $emailuser -xp $emailpasswd
}
crit_info=""
for(i=0;i<${#partition_list[@]};i+=2)
do
 if [ "${partiton_list[((i+1))]}" -lt "$critical" ]; then
  echo "OK ${partition_list[i]} used ${partition_list[((i+1))]}%"
 else
  if [ "partition_list[((i+1))]" -gt "$critical" ]; then
  crit_info=$crit_info"Warning!!!   ${partition_list[i]} used ${partition_list[((i+1))]}%\n"
  fi
 fi
done
if [ "$crit_info" != "" ]; then
 echo -e $crit_info | notification_email
fi
#磁盘监控脚本非常实用,设置告警阈值,超过阈值就发送邮件进行告警。sendEmail是个开源工具
#http://caspian.dotconf.net/menu/Software/SendEmail/下载最新版本
#互联网设置QQ邮箱:CentOS系统设置QQ邮箱
#第一步:网页打开QQ邮箱,设置》账户》IMAP/SMTP服务开启
#第二步:发送短信,获取授权码
#第三步:确认CentOS打开postfix服务命令systemctl status postfix,结果出现绿色字体的active(running)
systemctl status postfix
#第四步:确认是否安装mailx,命令which mailx
which mailx
#第五步:使用SMTP非加密端口发送邮件
cat >> /etc/mail.rc <<EOF
#显示的发件人,必须和用户认证邮箱一致
set from=*****@qq.com 
set smtp=smtp.qq.com
#smtp用户认证邮箱
set smtp-auth-user=*****@qq.com
#授权码
set smtp-auth-password=xxxxxxxxxxx
#默认是login,也可改为CRAM-MD5或PLAIN方式
set smtp-auth=login
EOF
#第六步:使用SSL加密方式,需要QQ邮箱的SSL证书,手动获取命令如下
#1、创建存放证书的目录
mkdir -p /root/.certs/
#2、获取QQ邮箱的SSL证书
echo -n | openssl s_client -connect smtp.qq.com:465 | sed -ne '/-BEGIN CERTIFICAT-/,/-END CERTIFICAT-/p' > ~/.certs/qq.crt
#3、添加第一个证书到证书数据库中
certutil -A -n "GeoTrust SSL CA" -t "C,," -d ~/.certs -i ~/.certs/qq.crt
#4、添加第二个证书到证书数据库中
certutil -A -n "GeoTrust Global CA" -t "C,," -d ~/.certs -i ~/.certs/qq.crt
#5、列出指定目录下的所有证书
certutil -L -d /root/.certs
#结果如:Certicate Nickname																								
#                Trust Attribute
#		        SSL,S/MIME,JAR/XPI
#        GeoTrust SSL CA 
#6、如果显示Error in certificate:Peer‘s certificate issuer is not recognized,运行如下命令
cd /root/.certs                                                                                         ll                                                                                         certutil -A -n "GeoTrust SSL CA - G3" -t "Pu,Pu,Pu" -d ./ -i qq.crt
#第七步:测试命令
echo 'This is a test.--From Postfix' | mail -s "Test Postfix" *****@qq.com

2.6.3批量自动创建用户

  • linux运维常需批量创建用户,用户名有规律,密码随机生成,用户名和密码都保存在文件中
#!/usr/bin/sh
#批量自动创建用户脚本
#默认会创建pws0~pws9这10个系统用户,用户名和密码保存在list_user文件中
DATE=`date "+%F_%T"`
USER_FILE=list_user
if [[ -s ${USER_FILE} ]]
then
 mv ${USER_FILE} ${USER_FILE}-${DATE}.bak
fi

echo -e "User\t Password" >> ${USER_FILE}
for USER in pws{0..9}
do
 if ! id ${USER} &>/dev/null
  then
   PASS=$(echo ${RANDOM} | md5sum | cut -c 1-8)
   useradd ${USER}
   echo -e ${PASS} | passwd --stdin ${USER} &>/dev/null
   echo -e "${USER}\t ${PASS}">>${USER_FILE}
   echo -e "${USER} USER CRERATE SUCCESSFUL"
 fi
done

2.6.4服务器状态监控脚本

  • 日常运维最常见的几种方式,通过脚本自动监控
  • 1、根据PID过滤进程所有信息
#!/bin/bash
#根据PID过滤进程所有信息
read -p "请输入要查询的PID:" p
n=`ps aux | awk '$2~/^'$p'$/{print $11}' | wc -l`
if [ $n -eq 0 ]; then
 echo "该PID不存在"
 exit
fi
echo "-------------------"
echo "进程PID: $p"
echo "进程命令:`ps aux | awk '$2~/^'$p'$/{print $11}'`"
echo "进程所属用户:`ps aux | awk '$2~/^'$p'$/{print $1}'`"
echo "CPU占用率:`ps aux | awk '$2~/^'$p'$/{print $3}'`"
echo "内存占用率:`ps aux | awk '$2~/^'$p'$/{print $4}'`"
echo "进程开始运行的时间:`ps aux | awk '$2~/^'$p'$/{print $9}'`"
echo "进程运行的持续时间:`ps aux | awk '$2~/^'$p'$/{print $10}'`"
echo "进程状态:`ps aux | awk '$2~/^'$p'$/{print $8}'`"
echo "进程虚拟内存:`ps aux | awk '$2~/^'$p'$/{print $5}'`"
echo "进程共享内存`ps aux | awk '$2~/^'$p'$/{print $6}'`"
echo "-------------------"
  • 根据进程名查看进程状态
#!/bin/bash
#根据进程名查看进程状态
read -p "输入进程名:" NAME
#统计进程总数
N=`ps aux | grep $NAME | grep -v grep | wc -l` 
if [ $N -le 0 ]; then
 echo "该进程名没有运行!"
fi
i=1
while [ $N -gt 0 ]
do
 echo "进程PID:`ps aux | grep $NAME | grep -v grep | awk 'NR=='$i'{print $0}' | awk '{print $2}'`"
 echo "进程命令:`ps aux | grep $NAME | grep -v grep | awk 'NR=='$i'{print $0}' | awk '{print $11}'`"
 echo "进程所属用户:`ps aux | grep $NAME | grep -v grep | awk 'NR=='$i'{print $0}' | awk '{print $1}'`"
 echo "CPU占用率:`ps aux | grep $NAME | grep -v grep | awk 'NR=='$i'{print $0}' | awk '{print $3}'`"
 echo "内存占用率:`ps aux | grep $NAME | grep -v grep | awk 'NR=='$i'{print $0}' | awk '{print $4}'`"
 echo "进程开始运行的时刻:`ps aux | grep $NAME | grep -v grep | awk 'NR=='$i'{print $0}' | awk '{print $9}'`"
 echo "进程运行的时间:`ps aux | grep $NAME | grep -v grep | awk 'NR=='$i'{print $0}' | awk '{print $11}'`"
 echo "进程状态:`ps aux | grep $NAME | grep -v grep | awk 'NR=='$i'{print $0}' | awk '{print $8}'`"
 echo "进程虚拟内存:`ps aux | grep $NAME | grep -v grep | awk 'NR=='$i'{print $0}' | awk '{print $5}'`"
 echo "进程共享内存:`ps aux | grep $NAME | grep -v grep | awk 'NR=='$i'{print $0}' | awk '{print $6}'`"
 echo "************************************"
 let N-- i++
done
  • 3、根据提供用户查看用户所有信息
#!/bin/bash
#根据提供的用户查询该用户的所有信息
read -p "请输入你要查询的用户:" A
echo "---------------------------------"
n=`cat /etc/passwd | awk -F: '$1~/^'$A'$/{print}' | wc -l`
if [ $n -eq 0 ]; then
echo "该用户不存在"
echo "---------------------------------"
else
 echo "用户名:$A"
 echo "用户的UID:`cat /etc/passwd | awk -F: '$1~/^'$A'$/{print}' | awk -F: '{print $3}'`"
 echo "用户的组为:`id $A | awk {'print $3'}`"
 echo "用户的GID为:`cat /etc/passwd | awk -F: '$1~/^'$A'$/{print}' | awk -F: '{print $4}'`"
 echo "用户的家目录:`cat /etc/passwd | awk -F: '$1~/^'$A'$/{print}' | awk -F: '{print $6}'`"
 Login=`cat /etc/passwd | awk -F: '$1~/^'$A'$/{print}' | awk -F: '{print $7}'`
 if [ $Login == "/bin/bash" ]; then
  echo "此用户有登陆系统的权限"
  echo "---------------------------------"
 elif [ $Login == "/sbin/nologin" ]; then
  echo "此用户没有登陆系统的权限"
  echo "---------------------------------"
 fi
fi

2.6.5Linux加固系统的自动化脚本

#加固系统是运维必备工作,脚本对系统用户和账号进行安全加固
#! /bin/bash
read -p "设置密码最长过期天数: " A
read -p "设置密码修改最短天数: " B
read -p "设置密码最短长度: " C
read -p "设置密码过期前警告天数: " D
sed -i '/^PASS_MAX_DAYS/c\PASS_MAX_DAYS '$A'' /etc/login.defs
sed -i '/^PASS_MIN_DAYS/c\PASS_MIN_DAYS '$B'' /etc/login.defs
sed -i '/^PASS_MIN_LEN/c\PASS_MIN_LEN '$C'' /etc/login.defs
sed -i '/^PASS_WARN_AGE/c\PASS_WARN_AGE '$D'' /etc/login.defs

echo "对密码已进行加固,新密码必须同时包含数字、小写字母、大写字母,且新密码不得和旧密码相同"
sed -i '/pam_pwquality.so/c\password requisite pam_pwquality.so try_first_pass local_users_only retry=3 authtok_type= difok=1 minlen=8 ucredit=-1 lcredit=-1 dcredit=-1' /etc/pam.d/system-auth

echo "对密码已进行安全加固,如果输入错误密码超过3次,就锁定账户"
n=`cat /etc/pam.d/sshd | grep "auth required pam_tally2.so" | wc -l`
if [ $n -eq 0 ]; then
 sed -i '/%PAM-1.0/a\auth required pam_tally2.so deny3 unlock_time=150 even_deny_root root_unlock_time300' /etc/pam.d/sshd
fi

echo "已设置禁止root用户远程登陆"
sed -i '/PermitRootLogin/c\PermitRootLogin no' /etc/ssh/sshd_config

read -p "设置历史命令保存条数:" E
read -p "设置账户自动注销时间:" F
sed -i '/^HISTSIZE/c\HISTSIZE='$E'' /etc/profile
sed -i '/^HISTSIZE/a\TMOUT='$F'' /etc/profile

echo "只允许wheel组的用户可以用su命令切换到root用户"
sed -i 'pam_wheel.so use_uid/c\auth required pam_wheel.so use_uid ' /etc/pam.d/su
n=`cat /etc/login.defs | grep SU_WHEEL_ONLY | wc -l`
if [ $n -eq 0 ]; then
 echo SU_WHEEL_ONLY yes >> /etc/login.defs
fi

echo "即将对系统中的用户进行检查"
echo "系统中有登录权限的用户有:"
awk -F: '($7=="/bin/bash"){print $1}' /etc/passwd
echo "-----------------------------------------------"
echo "系统中UID=0的用户有:"
awk -F: '($3=="0"){print $1}' /etc/passwd
echo "-----------------------------------------------"
N=`awk -F: '($2==""){print $1}' /etc/shadow | wc -l`
echo "系统中无密码的用户有:$N"
if [ $N -eq 0 ]; then
 echo "恭喜,系统中没有空密码用户"
 echo "-----------------------------------------------"
else
 i=1
 while [ $N -gt 0 ]
 do
  None=`awk -F: '($2==""){print $1}' /etc/shadow | awk 'NR=='$i'{print}'`
  echo "-----------------------------------------------"
  echo $None
  echo "必须为无密码用户设置密码"
  passwd $None
  let N--
 done
 M=`awk -F: '($2==""){print $1}' /etc/shadow | wc -l`
 if [ $M -eq 0 ]; then
  echo "恭喜,系统中已经没有空密码用户"
 else
  echo "系统中还存在空密码用户:$M"
 fi
fi

echo "即将对系统中重要文件进行锁定,锁定后将无法添加、删除用户和组"
read -p "警告:此脚本运行后将无法添加删除用户和组,确定输入Y,取消输入N;Y/N:" i
case $i in
 [Y,y])
  chattr +i /etc/passwd
  chattr +i /etc/shadow
  chattr +i /etc/group
  chattr +i /etc/gshadow
  echo "锁定成功"
  ;;
 [N,n])
  chattr +i /etc/passwd
  chattr +i /etc/shadow
  chattr +i /etc/group
  chattr +i /etc/gshadow
  echo "取消锁定成功"
  ;;
 *)
  echo "请输入Y/y or N/n"
esac

2.6.6检测MySQL服务状态脚本

  • 1、检查MySQL服务是否存活
#! /bin/bash
#host是需要检测的MySQL主机的IP地址,user为MySQL账户名,passwd为密码
host=172.16.213.30
user=root
passwd=xxxxxxxxx
mysqladmin -h '$host' -u '$user' -p '$passwd' ping &>/dev/null
if [ $? -eq 0 ]
then
 echo "MySQL is UP"
else
 echo "MySQL is down"
fi
#脚本借助mysqladmin命令
  • 2、检查MySQL主从同步状态
#MySQL主从复制架构在企业应用广泛,主从状态的监控也是运维的一部分
#! /bin/bash
USER=ixdba
PASSWD=xxxxxxxx
IO_SQL_STATUS=$(mysql -u $USER -p $PASSWD -e 'show slave status\G' | awk -F: '/Slave_.*_Running/{gsub(": ",":");print $0}')
for i in $IO_SQL_STATUS; do
 THREAD_STATUS_NAME=${i%:*}
 THREAD_STATUS=${i#*:}
 if [ "THREAD_STATUS" != "Yes" ]; then
  echo "Error:MySQL Master-Slave $THREAD_STATUS_NAME status is $THREAD_STATUS!"
 fi
done
#登陆MySQL,查询主从复制的两个状态值Slave_SQL_Running和Slave_IO_Running,两个值都是Yes则认为正常;
#USER和PASSWD是自己环境的数据库用户名和密码

2.6.7备份MySQL脚本

  • 1、基于mysqldump的备份脚本
#! /bin/bash
user=root
passwd=xxxxxxxx
dbname=mysql
date=$(date +%Y%m%d)
#测试备份目录是否存在,不存在则自动创建该目录
[ ! -d /mysqlbackup ] && mkdir /mysqlbackup
#使用mysqldump命令备份数据库
mysqldump -u "$user" -p "$passwd" "$dbname" > /mysqlbackup/"$dbname"-${date}.sql
#使用mysqldump命令方便,大量数据备份时力不从心
  • 2、通过mysqldump备份并压缩备份文件的脚本
#! /bin/bash
DATE=$(date +%F_%H-%M-%S)
HOST=172.16.213.220
DB=ixdba
USER=ixdba
PASS=xxxxxxxx
MAIL="[email protected] [email protected]"
BACKUP_DIR=/data/db_backup
SQL_FILE=${DB}_full_$DATE.sql
BAK_FILE=${DB}_full_$DATE.zip
cd $BACKUP_DIR
if mysqldump -h $HOST -u $user -p $PASS --single-transaction --routines --triggers -B $DB > $SQL_FILE; then
 zip $BAK_FILE $SQL_FILE && rm -f $SQL_FILE
 if [ ! -s $BAK_FILE ]; then
  echo "$DATE 内容" | mail -s "主题" $MAIL
 fi
else
 echo "$DATE 内容" | mail -s "主题" $MAIL
fi
find $BACKUP_DIR -name '*.zip' -ctime +7 -exec rm {} \;
#脚本通过mysqldump进行数据库备份,对备份的SQL文件进行压缩和校验,并删除一周之前的备份

2.6.8一键自动化安装Nginx脚本

#! /bin/bash
#一个简单的一键自动化安装脚本
function IXDBA(){
cat <<EOF
-----------------------------------------------------------------------------------------
                              一键安装Nginx脚本
-----------------------------------------------------------------------------------------
EOF                              
}
IXDBA
if [ ! -d /usr/local/src ]
then
 mkdir /usr/local/src
fi
LOG_DIR=/usr/localsrc
function NGINC_INSTALL(){
yum install -y gcc gcc-c++ pcre-devel zlib-devel openssl-devel &>/dev/null
 if [ $? -eq 0 ]
 then
  cd $LOG_DIR 
  && wget http://nginx.org/download/nginx-1.14.2.tar.gz &>/dev/null 
  && useradd -M -s /sbin/nologinnginx
  && tar -zxf nginx-1.14.2.tar.gz
  && cd nginx-1.14.2/
  && ./configure --prefix=/usr/local/nginx 
  --with-http_dav_module 
  --with-http_stub_status_module
  --with-http_additon_module 
  --with-http_sub_module 
  --with-http_flv_module 
  --with-http_mp4_module
  --with-pcre 
  --with-http_ssl_module 
  --with-http_gzip_static_module 
  --user=nginx &>/dev/null
  && make &>/dev/null
  && make install &>/dev/null
 fi
 if [ -e /usr/local/nginx/sbin/nginx ]; then
  /usr/local/nginx/sbin/nginx && echo "Nginx安装并启动成功!!!"
 fi
} 
echo "开始安装Nginx 请稍等..." && NGINX_INSTALL
#可以仿照nginx,编写一键安装MySQL、PHP、Zabbix

2.6.9查找指定网段活跃IP脚本

  • 查找指定网段内活跃的IP地址,查找结果自动重定向到ip.txt,以备查验
#!/bin/bash
read -p "please input a IPv4 netphase: " n
a=1
while :
do
 a=$(($a+1))
 if test $a -gt 255
 then break
 else
  echo $(ping -c 1 $n.$a | grep "ttl" | awk '{print $4}' | sed 's/://g')
  ip=$(ping -c 1 $n.$a | grep "ttl" | awk '{print $4}' | sed 's/://g')
  echo $ip >> ip.txt
 fi
 sed -i '/^$/d' ip.txt
done
cat ip.txt

2.6.10监控网站页面是否正常访问脚本

  • 监控网页状态是Web运维必备工作
#!/bin/bash
#监控网站页面是否正常访问
source /etc/profile
read -p "input a website you want to know whether ok or not ok:" website
A="Web is Ok"
ip=`/sbin/ifconfig -a | grep inet | grep -v 127.0.0.1 | grep -v 192 | grep -v inet6 | awk '{print $2}' | tr -d "addr:"`
ttl=`curl -I -s ${website} | head -1 | cut -d " " -f2`
Process=`ps -ef | grep java | grep -E "tomcat" | awk -F " " '{print $2}'`
if [ ${ttl} = "200" ]
then
 echo "${A}" >> website-log.`date +%F`.log
else
 echo ${ttl} ${Process} >> website-log.`date +%F`.log
fi

第3章 Linux系统运维深入实践

3.1Linux用户权限管理

3.1.1用户和用户组管理

1,用户与角色分类,linux用户是根据角色定义的,具体分三种角色

  • 超级用户,对系统拥有最高管理权限,默认是root用户
  • 普通用户,只能对自己目录下的文件进行访问和修改,具有登陆系统的权限,如WWW用户,FTP用户 等.
  • 虚拟用户,也叫"伪"用户,这类用户最大特点不能登陆系统,它们存在主要是方便管理,满足相应系统进程对文件属主的要求,系统默认的bin,adm,nobody用户等.

2,用户和组以及关系

  • Linux是一个多用户多任务的分时操作系统.使用系统资源必须向系统管理员申请一个账户,通过账户进入系统(账户和用户是一个概念).不同属性的用户:一方面合理地利用和控制系统资源;另一方面帮助用户组织文件,提供对用户文件的安全性保护`.
  • 用户组是具有相同特征用户的逻辑集合,有时需要多个用户具有相同权限,例如10个用户需要查看修改某一文件的权限:一种方法授权给10个用户;另一种方法,建立一个组,让这个组具有权限,再将需要权限的用户放入这个组.
  • 将用户分组是Linux系统中对用户进行管理及控制访问权限的一种手段.用户和用户组的关系:一对一,一对多,多对一,多对多.

3,用户和组相关的配置文件
(1)/etc/passwd文件

  • /etc/passwd文件是系统用户配置文件,是用户管理中最重要的文件.记录Linux系统中每个用户的基本属性,并且对所有用户可读,每一行记录对应一个用户,每行记录被冒号分隔
用户名:口令:用户标识号:组标识号:注释性解释:主目录:默认shell(共7项数据)
  • 口令,Linux使用shadow技术,真正加密后用户口令存放到/etc/shadow文件中,/etc/passwd只存放一个特殊字符,x或*表示.
  • 每个用户有一个UID,并且唯一,通常UID取值范围0-65535,0是超级用户root的标识号,1-99系统保留,普通用户标识号从100开始,Linux系统中,普通用户默认从500开始.UID是Linux系统下确认用户权限的标志.
  • 默认shell,用户登陆系统后使用的命令解释器.shell是用户和系统内核之间的接口.用户的任何操作都是通过shell传递给系统内核.管理员可以根据用户习惯给不同用户设置不同shell.

(2)/etc/shadow文件,root有读权限:

用户名:加密口令:最后一次修改时间:最小时间间隔:最大时间间隔:警告时间:不活动时间:失效时间:保留字段
  • 加密口令此字段为*,!,x等字符,则用户不能登陆系统
  • 不活动时间表示用户口令作废多少天后,系统会完全禁用此用户
  • 失效时间是账号的生存期,超过这个期限账号失效,用户无法登陆系统,字段值为空永久有效
  • 最后一次修改时间-最小时间间隔-警告时间-最大时间间隔-不活动时间-失效时间

(3),/etc/group文件

  • 用户组配置文件:
组名(字母和数字构成):口令(密码默认设置在/etc/gshadow):组标识符(GID):组内用户列表(用户之间用逗号隔开)

(4),/etc/login.defs

  • 定义创建一个用户时的默认设置
MAIL_DIR /var/spool/mail
PASS_MAX_DAYS 9999
PASS_MIN_DAYS 0
PASS_MIN_LEN 5
#口令到期前多少天警告用户
PASS_WARN_AGE 7
UID_MIN 500
UID_MAX 60000
GID_MIN 500
GID_MAX 60000
GREATE_HOME yes

(5),/etc/default/useradd
useradd命令不加任何参数创建一个用户,默认主目录位于/home,默认shell是/bin/bash

GROUP=100
HOME=/home 
#不启用账号过期禁用
INACTIVE=-1
#不设置账号过期日期
EXPIRE=
SHELL=/bin/bash
SKEL=/etc/skel
CREATE_MAIL_SPOOL=no

#改变此文件通过:1,文件编辑器;2,useradd命令.
useradd -D [-g group] [-b base] [-s shell] [-f inactive] [-e expire] 
#显示当前/etc/default/useradd当前设置
useradd -D

(6),/etc/skel

  • 创建一个新用户,新用户的主目录下.bash.profile,bashrc,bash_logout等文件
  • 变更/etc/skel目录下的内容就可以改变新建用户默认主目录的配置文件信息

3.1.2添加,切换和删除用户组命令groupaddd/newgrp/groupdel

1,groupadd命令

#-g 新建用户组的GID,唯一
#-o 一般与-g选项同时使用,新用户组的GID可与系统已用用户组GID相同
groupadd [-g -o] gid group

2,newgrp命令

#newgrp主要用于在多个用户组之间切换
useradd -g group -G group0 group1 user
su - user
newgrp [usergroup]

3,groupdel

#删除用户组
groupdel [usergroup]
#先删除该组用户才能删除用户组

3.1.3 添加,修改,和删除用户命令useradd/usermod/userdel

1,useradd建立用户的过程

  • useradd不带任何参数创建用户,系统首先读取配置文件/etc/login.defs和etc/default/useradd文件,根据这两个文件配置添加用户
  • 然后会向/etc/passwd和/etc/group两个文件添加用户和用户组记录
  • 同时加密文件/etc/passwd和/etc/group对应的加密文件也自动生成
  • 接着系统会在/etc/default/useradd文件设定的目录下建立主目录
  • 最后复制/etc/skel目录中的所有文件到新用户的主目录中

2,useradd的使用语法

useradd [-u uid [-o]] [-g group] [-G group,...] [-d home] [-s shell] [-c comment] [-f inactive] [-e expire] name
#-f inacitve指定账号过期多长时间后永久停用,当值为0时账号立刻被停用;当值为-1时则关闭此功能(预设值-1)
#-e expire指定用户的账号过期时间,日期的指定格式为MM/DD/YY

3,usermod的使用语法

#usermod修改用户的账户的属性信息
usermod [-u uid [-o]] [-g group] [-G group0,group1,,,] [-d 主目录 [-m]] [-s shell] [-c 注释] [-l 新名称] [-f 失效日期] [-e 过期日期] [-L|-U] Name
#-L锁定用户密码,使密码无效。-U解除密码锁定

4,userdel语法使用

#userdel用来删除一个用户
userdel -r user
#-r 不仅删除用户,还删除用户的主目录以及目录下的所有文件

5,应用举例

#添加一个用户mylinux
useradd -g root -G linux -d /opt/mylinux 
useradd -u 686 -s /bin/csh -G linux,fanlinux -c "this is a test" test_user
groupadd test_group
usermod -g test_group -G fanlinux,root -s /bin/bash test_user
#如何锁定密码,解锁用户密码
passwd test_user
su - test_user
#root切换到普通用户不需要密码,普通用户之间切换需要密码
usermod -L test_user
whoami
su - test_user
usermod -U test_user
su - test_user

3.1.4文件的权限属性解读

  • 文件权限是指对文件的访问权限,包括读,写,执行,删除等
  • 普通用户只能在自己的主目录下进行写操作,在主目录之外只能进行查找和读取操作
  • Linux常见的文件类型:
-#表示普通文件
d#表示目录
c#字符设备文件
b#块设备文件
s#套接字文件
p#管道
l#符号链接文件
.#代表当前目录
..#代表上级目录
ls 
ls -al #显示文件和目录的权限信息
#文档类型与权限,硬链接数,文档所属的用户和用户组,文档的大小,文档的最后修改时间,文档名称
#文档类型与权限:文档类型,文档拥有者的权限(user),文档所属用户组的权限(group),其他用户的权限(others)
chmod #文档的操作权限的制定和更改
#连接数,硬链接的概念,多少个文件指向同一个索引节点
ln install.log install.log1
ln install.log install.log2
#为install.log做了两个硬链接,install.log的连接数变为3
chown #修改文档的用户属性
#文档的大小默认以Bytes为单位,对于目录通常只显示文件系统默认block的大小
ls -sh #组合人性化的显示文档的大小
#文档名称,以"."开头的是隐藏文档。

3.1.5利用chown改变属主和属组

  • chown,是change owner的意思,主要作用是改变文件或目录的所有者,所有者包含用户和用户组
chown [-R] 用户名称 文件或目录
chown [-R] 用户名称:用户组织名称 文件或目录
#-R递归式的权限修改,进行操作前确保用户和用户组存在于系统

3.1.6利用chmod改变访问权限

  • 改变文件或目录的访问权限,有两种方法:一种是包含字母和操作符表达式的字符设定法;另一种是包好数字的数字设定法。

1,字符设定使用语法

chmod [who] [+|-|=] [mode] 文件名
#who表示操作对象,可以是下面字母中的一个或者他们的任意组合:
#u表示用户(user),即文件或目录的所有者;g表示用户组(group),即文件或目录所属的用户组;o表示其他(other)用户;a表示所有用户,它是系统的默认值
#操作符定义如下:
#+表示添加某个权限;-表示取消某个权限;=表示赋予给定的权限,同时取消文档以前的所有权限
#mode表示可以执行的权限,r,w,x(可读,可写,可执行),以及他们的组合
#文件名可以是以空格分开的文件列表,支持通配符wildchar
chmod u=rwx,g+r,o+r install.log
chmod u-x,g-r,o-r install.log

2,数字设定法

# 0表示没有任何权限,1表示可执行权限,2表示可写权限,4表示可读权限
chmod 755 mysql.sh

3.2Linux磁盘存储管理

  • linux系统所有硬件设备都是通过文件的方式来变现和使用,被称为设备文件。
  • linux下的/dev目录中有大量的设备文件,设备文件的不同:字符设备文件和块设备文件
  • 块设备文件是以数据块的方式来存取,最常见的设备就是磁盘;字符设备文件的存取是以字符流的方式进行,一次传送一个字符,常见设备打印机,终端TTY,绘图仪和磁带设备。

3.2.1磁盘设备在Linux下的表示方法

  • 常见磁盘类型:IDE并口硬盘,STAT串口硬盘,SCSI硬盘
  • linux系统下磁盘设备表示方案有两种:
  • 主设备号+次设备号+磁盘分区编号(IDE硬盘:hd[a-z]x;SCSI硬盘:sd[a-z]x)
  • 主设备号+[0-n],y (IDE硬盘:hd[0-n],y;SCSI硬盘:sd[0-n],y)
  • 主设备号代表设备类型,唯一确定设备的驱动程序和界面。次设备号代表同类设备中的序号,a~z表示设备的序号/dev/hda表示第一块IDE硬盘。
  • 系统只有一块硬盘,设备文件显示hdb,这与硬盘的跳线有关。
  • 磁盘分区编号,x表示没块磁盘上划分的磁盘分区编号,分区类似于Windows系统中的C盘,D盘的概念。hdax代表第一块磁盘的第X个分区。
  • 0-n表示同类磁盘的序号,y是数字表示,从1开始表示磁盘的分区编号,hd0,8与hda7是等同的

3.2.2 UEFI、BIOS和MBR、GPT之间的关系

  • 统一的可扩展固件接口(Unified Extensible Firmware Interface,UEFI)定义了操作系统和平台固件的接口标准,
    接口用于操作系统自动从预启动的操作环境(系统启动之后,操作系统开始运作之前)加载到操作系统上,开机程序化繁为简。
  • UEFI最准确的说是一种规范,不同厂商根据规范对UEFI进行实现,做出PC固件,这样的固件被称为UEFI固件。
  • 基本输入和输出系统(Basic Input Output System,BIOS),是最古老的系统固件和接口。采用汇编语言进行编程,使用中断来执行输入/输出操作确定PC生态系统的基本框架
  • UEFI比BIOS先进在:读取分区表;访问某些特定文件系统中的文件;执行特定格式的代码。
  • 主引导记录(Master Boot Record,MBR),即硬盘的主引导记录分区列表,硬盘的0柱面,0磁头,1扇区被称为主引导扇区(也叫主引导记录)。
  • MBR由三部分组成:主引导程序,硬盘分区表DPT和硬盘有效标志55AA。最多只能有四个表项,只能把硬盘分为四个主分区,或者分成<=3个主分区加1个扩展分区。不能识别大于2T的硬盘空间。
  • 总共512字节的主引导扇区,主引导程序Boot Loader占446字节。Partition Table区(分区表)即DPT占64字节。Magic number,占两个字节,固定为55AA。
  • 全局唯一标识分区列表(GUID Partition Table,GPT)是一个物理硬盘的分区结构,替代BIOS中的主引导分区记录(MBR),GPT没有分区数量限制可管理磁盘最大18EB,仅支持64位操作系统。
  • UEFI取代BIOS仅支持GPT,今年来UEFI主板大部分采用UEFI+BIOS共存模式,并且在BIOS中集成UEFI启动项。

3.2.3利用fdisk工具划分磁盘分区

1,#fdisk参数含义介绍,fdisk的使用格式:

#fdisk是linux系统下一款功能强大的磁盘分区管理工具。观察磁盘使用情况,对磁盘进行分割,相似工具cfdisk,parted等。
fdisk [-l] [-b SSZ] [-u] device
fdisk -l /dev/sda #-l查看制定设备的分区状况,选项后不加任何设备,则查看系统所有设备的分区状况
#-b SSZ 将指定的分区大小输出到标准输出上,单位为区块。
#-u,一般与-l选项配合使用,显示结果将用扇区数目取代柱面数目,用来表示每个分区的起始地址。
#device要显示或操作的设备名称。
#fdisk分为两个部分:查询部分和交互操作部分,通过fdisk进入命令交互操作界面,输入m显示交互操作下所有可使用的命令。
a #设定硬盘启动区 
b #编辑一个BSD类型分区
c #编辑一个DOS兼容分区
d #删除一个分区
l #查看制定分区的分区表信息
m #显示fdisk每个交互命令的详细含义
n #增加一个新的分区
o #创建一个DOS分区
p #显示分区信息
q #退出交互操作,不保存操作的内容
s #创建一个空的Sun分区表
t #改变分区类型
v #校验硬盘分区表
w #写分区表信息到硬盘,保存操作并退出
x #执行高级操作模式
d,l,m,n,p,q,w #常用选项。

2,fdisk实例讲解

#创建磁盘分区
#linux系统新增了一块硬盘,系统对应的设备名为/dev/sdb,现在通过fdisk对磁盘sdb进行分区划分
fdisk /dev/sdb
n #输入n创建一个新的分区
e #这里的e表示创建一个扩展分区
p #这里的p表示创建一个主分区
1 #主分区的编号从1~4,这里输入1
[Enter]#这里制定主分区的起始值,以柱面为单位计数,默认从1开始,直接按[Enter]键即可
+8G #这里指定分区的大小,直接输入需要的分区大小即可,例如,+1024M表示此分区大小1024M,+8G表示此分区大小为8G.
p #这里输入p显示分区情况,从下面可以看到,此分区已经建立起来。

#扩展分区也属于主分区,数字必需在1~4,且未使用。
#根据磁盘分区的划分标准,如果要建立扩展分区,最好将磁盘所有剩余空间都分给扩展分区,“p #这里的p表示创建一个主分区”这里直接按[Enter]键,磁盘剩余空间全部分给扩展分区。
l #这里的l表示创建一个逻辑分区
#修改磁盘分区类型
#linux系统下根据ID值区分不同的磁盘分区类型,fdisk默认创建的主分区和逻辑分区类型为Linux,对应的ID为83
#扩展分区默认为Extended,对应的ID为5.如果想要修改分区类型或者创建一个非默认的分区类型,需要交互参数t来指定。
t #输入t改变磁盘分区的类型
5 #要改变的磁盘分区对应的分区号,这里输入的5代表/dev/sdb5
L #通过L可以查看分区类型对应的ID值
7 #从上面的输出可知,7对应的分区类型为HPFS/NTFS
#分区的删除
#删除分区的参数是d,然后指定要删除的分区号,此分区就被删除了
fdisk /dev/sdb
d #这里输入删除分区的指令
6 #这里输入6表示要删除的分区是/dev/sdb6
#保存分区设置
#所有分区操作完成后,输入fdisk交互指令w即可保存分区设置退出;不保存分区设置按q退出。
#磁盘分区划分完毕,还是不能使用,还需将分区格式化为需要的文件系统类型。linux系统下默认支持EXT2,EXT3,EXT4,VFAT等文件系统。
mkfs.ext4 /dev/sdb1 #通过mkfs.ext4命令格式化分区/dev/sdb1
#分区格式化完毕,最后一步是挂载(mount)此设备。
mkdir /data
mount /dev/sdb1 /data
df | grep /data

3.2.4利用parted工具划分磁盘分区

1,fdisk只能对小于2T的磁盘进行划分分区,磁盘分区工具parted用于完成大于2T的磁盘分区工作
parted由GNU组织开发,功能更丰富:创建分区,调整分区大小,移动和复制分区,删除分区等.
parted分为两种模式:命令行模式(适合编程应用);交互模式简单方便.

2,parted使用方法

yum -y install parted
#parted进入交互模式
parted
#获取帮助信息
help
#创建分区,也就是设置使用msdos还是使用gpt格式.例如,模块mklabel gpt 标识设定分区表为gpt格式
mklabel gpt
#创建新分区命令.使用格式mkpart PART-TYPE [FS-TYPE] [START] [END]
#其中PART-TYPE表示分区类型,主要有主分区primary,扩展分区extended,逻辑分区logical,扩展分区和逻辑分区只针对MS-DOS分区表
#FS-TYPE表示文件系统类型,主要有:FAT32,NTFS,EXT,EXT3等,可不填写.
#START分区起始位置
#END分区的结束位置
mkpart primary EXT3 0gb 10gb
#输出分区信息,可简写为p,该功能由三个选项,free希纳是该盘的所有信息,并显示磁盘的剩余空间;
#number显示指定的分区的信息;all或list显示所有磁盘信息
print free
#删除分区.命令格式:rm number.例如:rm 3就是将磁盘分区3删除
rm 3
#选择设备,当输入parted命令后直接按[Enter]键进入交互模式时,默认设置是系统的第一块磁盘,如果系统有多块磁盘,需要用select命令选择要操作的硬盘
select /dev/sdb
#parted创建文件系统的功能有但较弱,一般是parted进行磁盘分区后,退出parted交互模式,用其他命令创建文件系统
mkfs.ext4 /dev/sdb1

3,parted应用实例

parted
select /dev/sdb 
p
mklabel gpt
mkpart primary 0gb 10gb
mkpart primary 10gb 15gb
p freee
mkpart primary 15gb 21.5gb
p
rm 3
mk.xfs /dev/sdb1
mkdir /data
mount /dev/sdb1 /data
df | grep /data

3.3 Linux文件系统管理

3.3.1线上业务系统选择文件系统标准

  • Linux系统中DOS文件系统类型MS-DOS;

  • Windows系统中FAT系列(FAT16和FAT32)和NTFS文件系统

  • 光盘文件系统ISO-9660

  • 单一文件系统EXT2和日志文件系统EXT3,EXT4,XFS

  • 集群文件系统GFS(Red Hat Global File System)

  • 分布式文件系统HDFS

  • 虚拟文件系统/proc

  • 网络文件系统NFS等

  • 1,读操作频繁同时小文件众多的应用(例如网站应用和邮件系统),选择EXT4文件系统.
    EXT3目录是线型,目录众多性能降低.
    EXT4延迟分配,多块分配和盘区功能,非常适合大量小文件的操作,更高效
    性能和安全方面考虑,XFS文件系统是较好选择

  • 2,写操作频繁的应用(大数据文件操作,应用本身需要大量日志写操作)
    XFS文件系统内是最佳的选择(效率更高,CPU利用率最好)
    XFS,EXT4,EXT3块写入性能差不多,效率由高到低XFS,EXT4,EXT3

  • 3,对性能和安全性要求不高的应用(Linux系统下/tmp采用EXT2文件系统)
    EXT3和EXT2文件系统是比较好的选择,EXT2没有日志记录功能,节省很多磁盘性能.

3.3.2网络文件系统(NFS)介绍

  • 网络文件系统(Network File System,NFS)主要实现的功能是让网络上的不同操作系统之间共享数据.
  • NFS首先在远程服务端(共享数据的操作系统)共享出文件或者目录
  • 共享出的文件或者目录通过挂载的方式挂接到本地的不同操作系统
  • 本地系统可方便地使用远端提供的文件服务,操作就像本地操作一样,从而实现数据的共享
  • NFS有两个部分组成,NFS Server和NFS Client.
  • NFS Server负责共享数据和相关权限设定,多个NFS Client端可同时挂载共享出来的数据到自己一个指定的目录

3.3.3NFS的安装和配置

以centos为例
1,安装NFS

#检查系统是否安装NFS相关服务
rpm -qa | grep rpcbind
rpm -qa | grep nfs

2,NFS Server端的设定

#NFS主要配置文件/etc/exports,格式如下:共享资源路径 [主机地址] [选项]
cat /etc/exports
/webdata *(sync,rw,all_squash)
/tmp *(rw,no_root_squash)
/home/share 192.168.1.*(rw,root_squash) *(ro)
/opt/data 192.168.1.18(rw)
/user/local/doc *.ixdba.net(rw,anonuid=686,anongid=686)
  • 客户端主机权限:
  • ro,rw
  • no_root_squash(信任客户端,登陆NFS主机用户是root,此用户对共享资源享有最高权限,此参数很不安全不建议使用)
  • root_squash(系统预设值,登陆NFS主机用户是root,权限缩为匿名使用者,UID和GID变成nfsnobody身份,只有可读权限,系统此预设值是为安全考虑)
  • all_squash(不管登陆NFS主机的是什么用户,共享文件的UID和GID映射为nfsnobody)
  • not_all_squash(系统预设值,保留共享文件的UID和GID默认权限,客户端用户的UID和GID和服务端文件的UID和GID相同时,才有对共享文件的读写权限,保证共享文件用户和组权限不会改变)
  • anonuid(将登陆NFS主机的用户都设成指定的UID,此UID必须存在于NFS Server的/etc/passwd文件中)
  • anongid(与上类似,用户组ID)
  • sync(资料同步写入磁盘中,默认选择)
  • async(资料会线暂时存放在内存中,不会直接写入硬盘)
#启动/停止NFS服务
#start启动服务,stop停止服务,restart重启服务,enable服务开机自启动
systemctl start/stop/restart/enable nfs
systemctl start/stop/restart/enable rpcbind
  • 启动服务后又修改/etc/exports文件,不需重启NFS服务,使用exportfs命令即可让修改生效
  • 用法:exportfs [-aruv] [Host:/path]
  • -a 全部mount或unmount /etc/exports中的内容
  • -r 重新mount /etc/exports中分享出来的目录
  • -u unmount目录
  • -v 在export的时候,将详细的信息输出屏幕上
  • Host NFS客户端主机地址
  • /path 指定NFS Server上需要共享出来的目录的完整路径
#通过exportfs命令临时增加一个共享策略
#临时策略,如果NFS服务重启,或者通过r参数重新mount后,该策略会消失,类似ifconfig命令
exportfs 192.168.60.108:/home/test_user
exportfs 

3,NFS客户端的设定

  • 客户端安装nfs-utils和rpcbind服务
yum -y install nfs-utils
systemctl start rpcbind
systemctl enable rpcbind
#如果NFS Server开启防火墙,最好关闭防火墙保证客户端正常连接
systemctl stop firewalld
systemctl diable firewalld
  • 挂载共享资源
#Hostname:用来指定NFS Server的地址,可以是IP地址或主机名
#/directory: 表示NFS Server共享出来的目录资源
#mountpoint: 表示客户端指定的挂载点.通常是一个空目录
mount -t nfs Hostname(orIP):/diretory /mountpoint
mount -t nfs 192.168.60.133:/mydata /data/nfs
  • 开机自动挂载nfs目录
#编辑/etc/fstab文件
192.168.60.133:/mydata /data/nfs nfs defaults 0 0
  • 卸载(umount)NFS目录
umount /mountpoint
umount /data/nfs

4,NFS Server的安全设定

  • NFS没有真正的用户验证机制,RPC远程调用中存在权限漏洞.
  • 合理设定/etc/exports共享的目录权限,最好使用anonuid,anongid权限,使NFS客户端权限降到最低
  • 不建议使用no_root_squash选项,除非客户端是受信任的
  • 根据需要,合理设置最佳的NFSD的COPY数目.
#Linux的NFSD的COPY数目,通过/etc/sysconfig/nfs启动文件中的RPCNFSDCOUNT参数进行设置
#默认是8个NFSD
systemctl restart nfs-config
systemctl restart nfs

3.4 Linux进程管理与监控

*进程是在自身的虚拟地址空间运行的一个独立程序.

3.4.1进程的分类与状态

1,进程的分类

  • 系统进程,执行内存资源分配和进程切换等管理工作.进程运行不受用户干预,root用户也不能干预系统进程的运行.
  • 用户进程,执行用户程序,应用程序或内核之外的系统程序而产生的进程,此类进程可在用户的控制下运行或关闭.
  • 交互进程,由一个shell终端启动的进程,执行过程中,需要与用户进行交互操作,可运行于前台,也可以运行与后台.
  • 守护进程,守护进程是一直运行的一种进程,经常在Linux系统启动时启动,系统关闭时终止,
    独立于控制终端并且周期性执行某种任务或等待处理某些发生的事情.例如httpd,crond进程

2,父进程与子进程

  • Linux系统中,进程ID(PID)是区分不同进程的唯一标识,大小有限制最大32768
  • UID和GID分别表示启动进程的用户和用户组,所有进程都是PID为1的init进程的都带。
  • 内核在系统启动的最后阶段,启动init进程。init进程是所有进程的父进程,PPID表示父进程
  • 父进程和子进程是管理和被管理的关系,当父进程停止时,子进程也随之消失,但是子进程关闭,父进程不一定终止

3.4.2进程的监控与管理

  • linux系统监控和管理进程的命令:ps,top,lsof和pstree四个最常见最有用的指令

1,利用ps命令监控系统进程

  • ps是Linux下最常用的进程监控命令STIME表示进程的启动时间,TTY表示进程所属的终端控制台
  • TIME表示进程启动后累积使用的CPU总时间,CMD表示正在执行的命令
#输出关于apache的信息
ps -ef | head -n 1;ps -ef | grep httpd
#查看父子进程的关系
#%CPU,%MEM,VSZ进程虚拟内存大小,RSS进程实际内存(驻留集)大小(单位是项),STAT表示进程的状态,START表示进程启动时间
#R正在运行中的进程,S表示处于休眠状态的进程,Z表示僵死进程,<表示优先级高的进程,N表示优先级较低的进程,s表示父进程,+表示位于后台的进程
ps -auxf | head -n 1;ps -auxf | grep httpd

2,利用top监控系统进程

  • 与ps命令相比,top命令动态、实时地显示进程状态。top命令提供了一个交互界面
  • 优先级PR,占用虚拟内存总量VIRT,未被换出的物理内存RES,共享内存SHR,进程启动到现在Java占用CPU总时间TIME+(单位1/100s),

3,利用lsof监控系统进程和程序

  • lsof列举系统中已经被打开的文件,可根据文件找到对应的进程信息,也可根据进程信息找到进程打开的文件
#lsof filename,显示使用filename文件的进程,COMMAND对应的字段表示使用文件的进程.
lsof /var/log/messages

#显示nfs进程现在打开的文件
#FD列表示文件描述符,TYPE列显示文件的类型,SIZE列显示文件的大小,NODE列显示本地文件的node码,NAME列显示文件的全路径或挂载点
lsof -c nfs 

#显示指定进程组打开的文件情况
#PGID列表示进程组的ID号,例如sendmail程序当前打开的所有文件,设备,库或套接字等
lsof -g gid 

#PID是进程号,通过进程号显示程序打开的所有文件和相关进程,例如想知道init进程打开那些文件
lsof -p PID

#通过监听指定的协议,端口,主机等信息,显示符合条件的进程信息.语法:
#lsof -i [46] [protocol] [@hostname] [:service|port]
#4代表IPv4,6代表IPv6,protocol传输协议可以是TCP或UDP,hostname主机名或者IP地址,
service进程的服务名例如NFS,SSH,FTP等,port系统中服务对应的端口号例如HTTP服务默认对应80端口,ssh服务默认端口22等.

4,利用pgrep查询进程ID

  • pgrep是通过进程的名字来查询进程PID的工具
#检查程序在系统中活动的进程,输出进程属性匹配命令行上指定条件的进程ID,
#每个进程ID以十进制表示,通过分隔字符串和下一个ID分开.
#判断程序是否正在运行,迅速直到进程PID的需求
pgrep 参数选项 command
#-l列出程序名和进程ID值,-o用来显示进程起始的ID值,-n用来显示进程终止的ID值,
#-f可以匹配command中的关键字,即为字符串匹配,-G可以匹配指定组启动的进程对应的ID值
pgrep -lo httpd
pgrep -ln httpd
pgrep -f sshd
pgrep -G www_data

3.4.3任务调度进程crond的使用

  • crond是Linux系统下周期性地执行某种任务或等待处理某些事情的一个守护进程
  • 默认安装此服务工具,并且会自动启动crond进程,crond进程每分钟定期检查是否有要执行的任务
  • Linux系统下任务调度分为两类,系统任务调度和用户任务调度
#系统任务调度,系统周期性所要执行的工作,如写缓存数据到磁盘,日志清理等
#在/etc/crontab文件,此文件就是系统任务调度的配置文件
cat /etc/crontab
#前4行用来配置crond任务运行的环境变量:系统使用哪个shell,系统执行命令的路径,crond的任务执行信息将通过电子邮件发送给root用户,执行命令或脚本时使用的主目录
SHELL=/bin/bash
PATH=/sbin:/bin:/usr/sbin/:usr/bin 
MAILTO=root
HOME=/
#run-parts
01 * * * * root run-parts /etc/cron.hourly
02 4 * * * root run-parts /etc/cron.daily
22 4 * * 0 root run-parts /etc/cron.weekly
42 4 1 * * root run-parts /etc/cron.monthly
#用户调度任务,用户定期要执行的工作,如用户数据备份,定时邮件提醒等.
#用户可以使用crontab工具定制自己的计划任务
#所有用户定义的crontab文件都被保存在/var/spool/cron目录中,其文件名与用户名一致

2,crontab工具的使用
(1)crontab的使用格式

#crontab常用的使用格式由如下两种
#-u用来设定某个用户的crontab服务,此参数一般由root用户来运行
#file是命名文件的名字,表示将file作为crontab的任务列表文件并载入crontab,如果未指定将接受标准输入
#-e编辑某个用户的crontab文件内容,如果不指定用户,则表示当前用户的crontab文件
#-l显示用户的crontab文件内容,如果不指定用户,则显示当前用户的crontab文件内容
#-r从/var/spool/cron目录中删除某个用户的crontab文件,不指定用户,则删除当前用户的crontab文件
#-i在删除用户的crontab文件时给确认提示

crontab [-u user] [file]
crontab [-u user] [-e|-l|-r|-i]

(2)crontab文件的含义

#用户所建立的crontab文件中,每一行都代表一项任务,每行的每个字段代表一项设置,共六个字段,前五个字段是时间设定段,第六段是要执行的命令段
#'*'代表所有可能值,','逗号隔开的值指定一个列表范围,'-'整数之间的中杠表示一个整数范围,'/'正斜杠指定时间的间隔频率
minute0-59 hour0-23 day1-31 month1-12 week0-7sunday command系统命令&脚本文件
0 */3 * * * /user/local/apache2/apachectl restart
30 3 * * 6 /webdata/bin/backup.sh
0 0 1,20 * * fsck /dev/sdb8
10 5 */5 * * echo " " >/user/local/apache2/log/access_log

3,使用crontab工具的注意事项
(1)注意环境变量问题

  • 创建crontab,任务无法自动执行,手动执行没问题,一般由于crontab文件没有配置环境变量
  • 手动执行是在当前shell环境下进行,系统自动执行调度任务时,不会加载任何环境变量,需要指定任务运行所需的环境变量

(2)注意清理系统用户的邮件日志

  • 每条任务调度执行完毕,系统都会将任务输出信息,通过电子邮件形式发给当前系统用户
  • 日志信息量大,会影响系统正常运行,将每条任务重定向处理非常重要
# >/dev/null 2>&1 先将标准输出重定向到/dev/null,然后将错误重定向到标准输出,标准输出和错误输出都输出到/dev/null
0 */3 * * * /usr/local/apache2/apachectl restart >/dev/null 2>&1

(3)系统级任务调度和用户级任务调度

  • 系统级任务调度主要完成系统维护操作,用户级任务调度是完成用户定义的任务
  • 用户级调度任务放到系统级调度任务完成(不建议这样做),反过来却不行
#root用户的任务调度操作通过crontab -u root -e来实现
#或者将调度任务直接写入/etc/crontab文件
#定义一个定时重启系统的任务,必须放到/etc/crontab文件
crontab -u root -e 

3.4.4如何关闭进程

1,用kill终止一个进程

#关闭某些服务,关闭处于僵死状态的进程,Linux关闭进程用kill命令.
#首先向操作系统内核发送一个终止信号和终止进程的PID,系统内核根据发送的终止信号类型对进程进行相应的终止操作
kill [信号类型] 进程PID
#查看所有信号类型
kill -l
#强制结束进程
kill -9
#结束进程,非强制性.和[Ctrl]+[C]
kill -2
#正常结束进程,kill的默认选项,kill不加任何信号类型时默认类型就是15
kill -15
kill 
#强制关闭一个Apache子父进程,Apache子进程没有因为父进程关闭而自动关闭
#子进程存在,子进程的PPID由原来的5078变成1,这是正常关闭和强制关闭的区别
kill -9 5078
#正常关闭进程,父进程终止时,会同时调用资源关闭子进程,释放内存
#强制关闭进程操作中,忽略进程之间的依赖关系,父进程直接关闭,不去理会子进程
#子进程成了孤儿进程,为让孤儿进程的资源得以释放,系统默认将init进程作为孤儿进程的父进程
#只需要再次执行kill命令关闭相应的子进程即可

2,用killall终止一个进程

  • killall后面跟的是进程的名字,而不是进程的PID,killall可以终止一组进程
#kill的使用语法
#信号类型,与kill中信号类型含义一致
#进程名称,进程对应的名称,例如java,httpd,mysqld,sshd,sendmail等
killall [信号类型] 进程名称
killall httpd

你可能感兴趣的:(linux,运维)