linux之shell基本认知操作和简单shell练习
shell编程:
1.Shell的作用
命令解释器,“翻译官”。介于操作系统内核与用户之间,负责解释命令行。
shell功能非常强大,除负责解释名另外,还可以将多个命令组合起来,完成复杂的任务,这就是SEHLL编程。
CentOS7之前(Linux核心3.0之前)的各版本都是通过shell程序进行服务控制的。
1.编译器
将系统外围使用高级语言(如:JAVA、C#等)编写的程序 翻译成系统内核 及硬件能够 识别的低级程序 或机器语言程序的工具,称为编译器
编译器其实也是一个程序,不同操作系统的编译器也不同。
shell是另外一种程序的执行方式,解释执行。
shell有很多的版本,如:sh、ksh、csh、bash等,RHEL(redhat、CentOS)常用的是bash
2.可以执行的命令(linux系统中)
二进制程序
shell程序
函数
别名
别名
命令别名
功能:给一个复杂的、较长的命令起一个简化的代用命令
alias jinWang="cd /etc/sysconfig/network-scripts"
alias ---查看系统中所有命令别名
unalias jinWang ---取消别名
传统的shell有3种:
Born SHELL-------------------sh
Korn SHELL ------------------ksh
C SHELL -------------------csh
linux系统支持多种shell。但常用的是bash -- Born Again Shell。Linux系统中的/etc/shells文件记录了系统支持的有效登录Shell。
每一种shell都支持如:
重定向
管道
作业控制 jobs fg bg &等功能,这些功能可用于shell程序控制,即shell编程。
3.切换shell环境
Linux支持的shell都可以使用。可以随时切换
临时切换:
直接执行其他Shell程序,示例ksh、zsh等
永久更改:
更改用户登录Shell:
需修改 /etc/passwd 文件中用户记录的最后一个字段
或执行:
usermod -s Shell程序路径 用户名
最简单的shell编程就是shell命令的罗列:
my_prog
date
pwd
ls -l
abc
whoami
echo "My test messages"
脚本基本编写:
以"#"开头的行shell不执行,都是注释,但第一行是"#!"例外。
#!/bin/bash ---指定脚本的shell
4.脚本的执行:
1.方式一:通过shell,调用脚本
bash /shell/my_prog
特点:脚本可以没有执行权限
2.方式二:有执行权限,缺省的shell或指定的shell("#!")
/shell/my_prog ---输入脚本的绝对路径,执行脚本,前提要求:脚本必须有执行权限
cd /shell --进入脚本所在目录
./my_prog --- . 表示当前路径
说明:
系统中的shell是一个程序,为了实现多任务处理,shell在执行命令时,并不是自己执行,而是再调用另一个shell去执行,被调用的shell称为子shell。而调用用子shell的shell称为子shell的父shell。输入exit,可以退出shell。
3.方式三:不开启子shell,在当前shell中运行脚本
source /shell/my_prog --- source 表示当前shell
或 . /shell/my_prog
cd /shell
. ./my_prog --- .前后有空格,表示当前shell,等同于source ; .后紧跟/,如: ./ 表示当前目录
观察子shell
ps -ejH
pstree
输入输出数据流:
标准输入 stdin
标准输出 stdout
错误输出 stderr
文件描述符 0 1 2
2.shell变量
shell变量是用来代表某个值的符号名,变量是shell传递数据的一种方法。
为灵活管理,Linux系统提供特定参数,
有两层意思:
变量名:使用固定的名称,由系统预设或用户定义
变量值:能够根据用户设置、依系统环境变化而变化
()子shell执行
{}当前shell执行
3.shell变量的种类
1)环境变量:由系统维护,用于设置用户的Shell工作环境,只有极少数的变量用户可以修改
2)预定义变量:Bash预定义的特殊变量,不能直接修改
3) 用户自定义变量:由用户自己定义、修改和使用
1.环境变量
指定、标识shell工作的环境的变量,称为环境变量
1.常用环境变量:
PS1 命令提示符
SHELL 当前shell版本
HOME 当前用户的家目录路径
PATH 命令搜索路径,指定系统到哪些目录下查找命令所对应的程序
echo $PATH ---查看环境变量的值,$符功能提取变量的值,环境变量必须大写
set ---显示所有环境变量设置
env ---显示系统主要的环境变量
unset LANG ---清空语言环境变量
2.更改换环境变量
PS1="{\u@\h \t \W}\\$" ---更改环境变量的值
注: \u 用户名 \h 主机名 \t 时间 \d 日期 \W 相对路径 \w 绝对路径 \\$身份符
shell在运行时,都拥有一套环境变量配置(/etc/profile、~/.bash_profile或shell程序中自己定义),shell打开,环境变量启用,shell关闭,环境变量删除。
shell程序中定义的变量,父shell通过将变量输出(export)可以递归传递给子shell。但子shell的变量永远不能传递给父shell。
预定义变量:
1.位置变量(传递参数)
linux的命令,都有大量的选项和参数,为在编写shell脚本时,也能使用这些选项和参数,就需要为shell程序定义相应的选项和参数(shell程序也是linux命令的一大类),将这些选项和参数传递给程序里的命令,就要使用变量,shell采用使用数字变量来表示位置参数,
1表示第一个参数,引用变量时,变量前加$前缀,表示为$n,n为数字。超过9要用{}。
位置变量0:当前执行的进程/程序名
2.状态变量:
shell程序本身及shell程序里的命令,运行状态的识别,就使用状态变量。
3.表示形式如下:
$#:命令行中位置参数的数量
$*:所有位置参数的内容,作为一个参数出现
$@: 所有位置参数的内容,作为多个参数出现,每个参数都是单个内容。
$?:上一条命令执行后返回的状态,当返回状态值为0时表示执行正常,非0值表示执行异常或出错
$$:当前所在进程的进程号
$!:后台运行的最后一个进程号
4.保留字
linux中具备特殊含义的字符、符号
* ---通配符,表示任意长度的任意字符
? ---单配符,表示一位长度的任意字符
[ ] ---单字符的取值范围,如:[0-9] [a-z] [A-Z] [02468]
[^ ] ---单字符的排除范围, 如:[^0-9] [^a-z]
{ } ---多字符取值范围,如:{ab,ac,bc} {a,b,c,d}
---[[:digit:]] 表示数字,同 [0-9]
---[[:lower:]] 表示小写字母,同 [a-z]
---[[:upper:]] 表示大写字母,同 [A-Z]
---[[:alpha:]] 表示所有的字母,同[a-zA-Z]
---[[:alnum:]] 表示字母+数字,同[a-zA-Z0-9]
---[[:space:]]空格,同[ ]
---[[:punct:]] 标点符号
"" ---用于明确参数的范围,一般在同一个参数内有空格时使用,如:date +"20%y-%m-%d %H:%M:%S"
'' ---引号嵌套时使用,明确引号的层次,如:echo 'i say :"hello"'
`` ---所引起来的内容当命令执行后,把执行结果交给其他操作,如:echo "the time is: `date`"
$ ---变量值提取符,用户身份
\ ---转义字符,提取、显示字符的引申含义,如 :rm -rf \*
| ---管道符,格式:前后两个命令,前命令的结果,当做后命令的输入用,如: ll /etc/ | less
> ---输出重定向,格式:前命令后文档,前命令的结果,保存到后文档中
> 表示覆盖 >> 表示追加 活用:> f1 ---清空文档内容
< ---输入重定向,格式:前命令后文档,把后文档中的文字,当做前命令的输入信息使用
如:write zhang < /mnt/f1
& ---后台执行符,命令后+ & ,表示把命令放入后台执行
如:find / -name f1 &
jobs ---查看后台进程
&& ---命令连接执行,如: echo aaa && echo bbb && echo ccc
注:前面的命令必须正确执行后,才会运行后面的命令
用户自定义变量
定义新的变量:变量名要以英文字母或下划线开头,区分大小写
格式:
变量名=变量值
赋值号的两边没有空格
没有变量值的变量是空变量。
如:
var1=
查看变量的值
格式:
echo $变量名
在使用变量值时,要在变量名前加上前缀“$”。
变量是程序执行过程中,临时存放数据的空间,变量会在内存中开辟一块空间,存入数据,程序结束,变量释放内存
示例:
shu=5 ---变量的声明与赋值,声明即到内存中开辟空间,赋值是存入数据
xingMing=zhangsan --- =左边是变量名,=右边是赋的值
echo $shu ---输出变量的值,用$做变量值的提取
echo ${shu}a ---用{}明确变量名,结果:5a
shu1=3
shu2=5
read shu --- read表示从键盘输入数据,赋值给变量
riQi=`date +"20%y-%m-%d %H:%M:%S"` ---把命令的执行结果赋值给变量,又称为命令结果替代
riQi=$(date +"20%y-%m-%d %H:%M:%S")
命令结果替代
val=date
val=`date` esc下的反引号,会输出时间
echo $val
或者
val=$((date))
echo $val
去除指定字符
shu=abc123
shu2=${shu%%1*} --- %%去除右侧的指定字符,结果 shu2=abc
shu3=${shu##*c} --- ##去除左侧的指定字符,结果 shu3=123
4.基本的算数运算
计算整数表达式的运算结果
格式:
expr 变量1 运算符 变量2 ...[运算符 变量n]
1.expr的常用运算符
加括号改变运算优先级,先乘除后加减,只能计算整数,不能算小数,负数也可以运算
加法运算:+
减法运算: -
乘法运算: \*
除法运算: /
求模(取余)运算: %
[root@cuug ~]# a=1
[root@cuug ~]# b=2
[root@cuug ~]# c=`expr $a + $b` 运算符号两端要空格
[root@cuug ~]# echo $c
3
[root@cuug ~]# c=`expr \( $a + $b \) \* $b` 运算符号两端要空格,并且()和*都要使用转意符“\”
[root@cuug ~]# echo $c
6
使用let命令格式更友好,但有些Shell不支持。
[root@cuug ~]# let c=a+b
[root@cuug ~]# echo $c
3
[root@cuug ~]# let c=(a+b)*b
[root@cuug ~]# echo $c
6
bash中,算数表达式:$(( $var1 + $var2 )),不用命令结果替代
a=2
B=3
Kwz=$(($a*$b))
Echo $kwz
6
5.逻辑操作符
1)逻辑与&&:可以把两个命令联系在一起
形式:命令1 && 命令2
功能:先运行命令1,如果成功,才运行命令2,否则不运行命令2
2)逻辑或||:命令互补
形式:命令1 || 命令2
功能:先运行命令1,不成功运行命令2,否则不运行命令2.
试比较下面的例子:
[root@cuug ~]# ls -l;date;uptime;LS;ls
[root@cuug ~]# ls -l && date && uptime && LS && ls
[root@cuug ~]# ls -l || date || uptime || LS || ls
成组命令,又叫命令块
在shell中可以使用2种方式将若干命令组合在一起,只返回一个逻辑结果。
使用花括号{}
使用圆括号()
以花括号括起来的命令可视为语法上的一条命令。命令块的执行顺序是根据命令出现的先后次序,由左向右由上到下执行。
在使用花括号时在格式上应注意,左括号“{”后面应有一个空格;右括号“}”之前应有一个分号“;”。
在使用(){} 也可以包含若干单独占一行的命令。
但()中的执行是子shell。{}是当前shell执行。
案例
[root@centos7 ss]# { ls
> pwd
> }
date.err date.log kk ss_ss
/ss
[root@centos7 ss]# ( date
> pwd
> )
2019年 10月 10日 星期四 08:38:44 CST
/ss
三.Shell练习
1.查找文件软件包名字
CentOS7系统上缺少文件,编写一段sehll程序,将CentOS7系统影像盘上包含该文件的软件包名找出来,不能用yum命令,只能使用rpm命令。CentOS光盘挂载到/mnt目录下。
vi wenjian
mount -r /dev/cdrom /mnt ---挂载
for i in `ls /mnt/Packages/*x86_64*`
do
rpm -qpl "$i" |awk -F "/" '{print "$NF"}'|grep "^$1$" 2>&1 > /dev/null
if [ "$?" -eq 0 ]
then
echo "$i"
fi
done
umount /mnt
注释
rpm -qpl "$i" ---查找rpm $1 安装包
|awk -F "/" '{print "$NF"} -- awk -F表示匹配 “/”字段
Print输出显示文件名, --$NF是number finally,表示最后一列的信息
|grep "^$1$" --匹配 $1, 这一行只包括文件名,比较精确|grep "$1"
rpm -qpl 软件包.x86_64.rpm 查找 rpm包
2.shell程序 创建用户
写一段shell程序,用于批量创建用户,用户的信息可以从文本文件中获得,文本文件的格式如下:
zhang.san@offcn.com 18120423679
li.si@121.com 18812343490
......
要求:
1、用户名是文件中邮件的用户名,但不能出现“.”,使用“zhang_san”格式的用户名。
2、用户的口令是手机号的后6位
3、每个用户初次登陆都要修改自己的口令
for i in `awk '{print $NF}' "$1"`
do
user_name=`grep "$i" "$1" |awk -F "@" '{print $1}'|sed 's/\./_/g'`
u_passwd=`echo "$i" |cut -b 6- `
/usr/sbin/useradd "$user_name" >/dev/null 2>/root/create_u.err
echo "$u_passwd" |/usr/bin/passwd --stdin "$user_name" > /dev/null 2>/root/u_passwd.err
/usr/bin/passwd -e "$user_name" > /dev/null 2>/root/passwd_del.err
Done
注释
echo 输出变成数据流
for i in `awk '{print $NF}' "$1" ` ---$NF匹配手机号,文件最后一个字段,“$1”是给awk文件的
do ---处理
grep "$i" "$1" -- 查找用户名 $1 =name _file
#grep 1813200022 name file ---会显示这一行内容
|awk -F "@" '{print $1}' ---分割@ 这个字段 找出名字 输出$1
|sed 's/\./_/g'` ---sed ‘s/\./_/g’ -/ /中 . 改为 _
或者 |awk -F “\” ’{print $1 ”_” $2}’ --zhang. Li . 改为_
u_passwd=`echo "$i"|cut -b 6-` --输出$1, 从第六位开始截取
/usr/sbin/useradd "$user_name" ---路径,添加用户
echo "$u_passwd" |/usr/bin/passwd --stdin "$user_name" --设置用户名字
/usr/bin/passwd -e "$user_name" --用户下次登陆得设置口令
输出
>/dev/null 2>/root/create_u.err 设定正确到第一个 错误第二个
> /dev/null 2>/root/u_passwd.err
> /dev/null 2>/root/passwd_del.err
3.删除僵尸进程
4、CentOS7系统上最近常出现“僵尸”进程,编写一段shell程序,将检查是否出现“僵尸”进程,每隔半个小时检查一次,如果出现“僵尸”进程,将出现“僵尸”进程的用户名和检查时间记录到文件中。
命令
vi find_process.sh
ps aux|awk '{print $11}'|grep "defunct" defunct --失效
if [ "$?" -eq 0 ]
then
/usr/bin/date >>/root/bad_pro_user bad_pro_user--记录路径
ps aux|awk '{print $1,$11}'|grep "defunct"|awk '{print $1}'>>/root/bad_pro_user
kill -9 `ps aux|awk '{print $2,$11}'|grep "defunct" |awk '{print $1}'`
fi
chmod a+x find_process.sh
systemctl status crond --查看服务
systemctl stop crond --关闭服务
crontab -e ---写计划任务
0,30 * * * * /root/shell/find_process.sh ---整点30分,执行脚本
~
systemctl start crond ---开启服务
注释
grep 查找的文件进程
ps aux|awk '{print $11}'|grep "defunct" ---ps查看进程,awk grep查找
if [ "$?" -eq 0 ] ---echo $? 查看 =0为有僵尸进程
/usr/bin/date >>/root/bad_pro_user ---date路径 ,写到root下文件中
ps aux|awk '{print $1,$11} ---找出来用户名$11和进程名字$1
'|grep "defunct"|awk '{print $1}' ----grep 查找僵尸进程,输出用户名字
>>/root/bad_pro_user ---记录到这个文件中
kill -9 `ps aux|awk '{print $2,$11}' ---删除$2 进程号 ,用户$11
'|grep "defunct" |awk '{print $1}'` ---针对awk这个字段,所以为$1
vi jiangshi.sh
ps aux|awk '{print $11}'|grep "defunct"
if [ "$?" -eq 0 ]
then
/usr/bin/date >>/bad_js
ps aux|awk '{
print $1,$11}
'|grep "defunct"|awk '{
print $1}
'>>/bad _js
kill -9 `ps aux|awk '{ print $2,$11}'|grep "defunct" |awk '{print $1}'`
fi
chmod a+x jiangshi.sh
systemctl status crond
systemctl stop crond
crontab -e
0,30 * * * * /bad_js/jiangshi.sh
systemctl start crond