18.Linux Shell编程基础与Shell环境
1.Linux Shell编程基础
2.Linux Shell变量
3.Linux Shell正则表达式
4.Linux Shell条件判断与流程控制
笔记:
1.Linux Shell编程基础
Shell是什么?
Shell是一个命令行解释器,它为用户提供了一个向Linux内核发送请求以便运行程序的系统级程序。
Shell本身是一个用C语言编写的程序,功能强大,易编写,易调试,灵活性强。
它是用户使用Unix/Linux的桥梁,用户的大部分工作都是通过Shell完成的。
Shell既是一种命令语言,又是一种程序设计语言。
Shell是解释执行的语言,能直接调用Linux系统命令。可以说,
shell使用的熟练程度反映了用户对Unix/Linux使用的熟练程度。
Shell分类: Bourne Shell:sh、ksh、Bash、psh
C Shell:csh、tcsh
Shell有两种执行命令的方式:
交互式(Interactive)
批处理(Batch)
Shell初学者请注意,在平常应用中,建议不要用root账号运行shell。
Linux的echo命令,在shell编程中极为常用,在终端下打印变量value的时候也是常常
用到的。
echo [选项] "输出内容"
选项:-e 支持反斜杠控制符
\a:输出警告音
\n:换行符
\r:回车符
\b:退格键
\t:水平制表符
\v:垂直制表符
\x:16进制ASCII码输出字符
echo "hello itpux" 显示hello itpux
shell别名:
alias
查看系统中已有的别名
alias ls='ls -lsa'
设置别名,要永久生效需将该命令放入~/.bashrc文件或~/.bash_profile中
unalias ls 删除别名
Bash shell中常用快捷键:
ctrl+c
强制终止
ctrl+l
清屏
ctrl+u
从光标位置删到行首
ctrl+a
从光标位置移到行首
ctrl+e
从光标位置移到行尾
ctrl+z
命令放到后台
shell多命令执行:
命令1;命令2
分号;表示多个命令顺序执行
命令1&&命令2 逻辑与,命令1执行正确则执行命令2,命令1执行错误则
不执行2
命令1||命令2 逻辑或,命令1执行正确则不执行2,命令1执行不正确则
执行命令2
SHELL重定向:
01.标准输出重定向
命令 > 文件
覆盖的方式写入
命令 >> 文件
追加的方式写入
02.标准错误输出重定向
错误命令 2> 文件
错误命令 2>> 文件 (注意:2和>之间无空格)
03.正确和错误信息同时重定向
命令 > 文件 2 > &1
命令 >> 文件 2 > &1
命令 &> 文件
命令 >> 文件 1 2>>文件2
正确和错误信息分开保存
ls -lsa > /dev/null
不想要的打印信息全部重定向到/dev/null下,输入到此的文件全被系统丢掉。
04.输入重定向
wc < 1.log
统计文件中的行数、单词书、字节数
Shell管道符:
命令1|命令2:命令1的正确输出作为命令2的输入
例:ls -lh /etc | more
用more命令分屏显示ls的输出结果
ps -ef| grep LOCAL=NO
查看进程,grep从搜索结果中查看LOCAL=NO的进程
ps -ef| grep LOCAL=NO |wc -l
查看进程,grep从搜索结果中查看LOCAL=NO的进程,并统计行数
Shell通配符:
?
匹配任意一个字符
*
匹配任意内容
[]
匹配括号内任意一个字符
[0-9]
-表示范围,匹配其中一个
[^0-9]
逻辑非^,匹配非括号内内容
Bash中其它符号:
$
调用变量的值
\
转义符,跟在\之后的特殊符号将失去特殊含义,如\*就是输出*号
#
Shell中表示注释
$()
用来引用系统命令
Shell历史命令:
Bash的历史命令保存在~/.bash history里
history
命令显示历史命令
history -c 清空历史命令
history -w 将本次开机以来的命令写入历史命令文件
SHELL简单的执行跟踪:
set -x命令打开跟踪功能,在此之后shell会显示每条被执行的命令,前面附带+号
set +x 关闭跟踪功能
例如:
#! /bin/bash
set -x
echo 1 itpux
set +x
echo 2 itpux
执行结果:
+echo 1 itpux
+set +x
echo 2 itpux
shell中用到的特殊文件:
/dev/null
它等价于一个只写文件,所有写入它的内容都会永远丢失,而尝试从它那儿读取内容则什么也
读不到。然而/dev/null对命令行和脚本都非常的有用。
nohup ./start.sh >/dev/null &
/dev/zero 会提供无穷无尽的0,它可以给文件写入无穷无尽的0
dd if=/dev/zero of=itpux.txt bs=1M count=10
/dev/tty
系统当前终端
cat 1.txt > /dev/tty
/dev/console 代表的系统控制台,错误信息和诊断信息都会被到这个上。
cat 1.txt >/dev/tty
2.Linux Shell变量
Bash Shell变量主要分为4种:
用户自定义变量、环境变量、位置变量、预定义变量。
本文主要介绍这4种变量:
1、用户自定义变量
只能作用于当前shell,变量取值都是一个字符串
DAY=date
"="左右两边不能有空格
DAY="today is date"
若含有空格,则需要加双引号
echo $DAY
$调用变量,echo打印输出
unset DAY
删除变量
set
该命令查看系统所有变量及其值
2、环境变量
全局的,所有shell都可以调用的变量
export DAY=date
export命令就是将变量导出为环境变量
env
env命令是查看系统所有的环境变量
环境变量PATH:为系统命令搜索的路径。
PATH="$PATH":/usr/sbin 即添加/usr/sbin目录也为PATH变量,若想要永久更改环境
变量,需要修改环境变量配置文件。
3、变量参数
$n n为数字,$0代表命令本身,$1-$9代表第1-9个参数,10以上的需要用大括号 ${10}
$* 代表命令行中所有参数,$*把所有参数当做一个整体
$@ 代表命令行所有参数,$@把每个参数区分对待
$#
代表命令行中参数的个数
$?
{BANNED}最佳后一次执行的命令的返回状态。若为0,则表示命令执行正确;若为非0,代表上一条
指令执行错误。
$$
当前进程的进程ID号
$!
后台运行的{BANNED}最佳后一个进程的进程号
4、环境变量配置文件
4.1 source命令 修改配置文件后使之生效
source 配置文件
或者 .配置文件
如:source /etc/profile; ./.bash_profile
4.2 常用环境变量配置文件
/etc/profile
/etc/profile.d/*.sh
~/.bash_profile
~.bashrc
/etc/bashrc
4.3 其他环境变量配置文件
01.注销时生效的文件:~/.bash_logout
如可以在每次注销时清空历史命令,将history
-c 写入该文件(但一般不建议)
02.历史命令保存文件:~/.bash_history
03.本地shell登录欢迎信息:/etc/issue
该文件中用到的转义符,/d 显示当前系统日期,/s 操作系统名称,/m 硬件体系结构,
/r 内核版本,/t 系统时间,/l 登录的终端号,/o 域名,/n 主机名
04.远程登录欢迎信息:/etc/issue.NET
要显示此信息,需要SSH配置文件/etc/ssh/sshd_config中要加入"Banner /etc/issue.Net"
05.登陆欢迎信息:etc/motd
不管是本地还是远程登录都能显示此信息。
3.Linux Shell正则表达式
正则表达式的介绍:
正则表达式是描述字符排列和匹配模式的一种语法规则。
正则表达式主要用于字符串的模式分割、匹配、查找及替换。
正则表达式主要为了模糊匹配。
正则表达式与通配符区别:
01.通配符(* ? [])用来匹配符合条件的文件名,是完全匹配。
ls、find、cp这些命令不支持正则表达式,支持通配符匹配。
02.正则表达式用来匹配在文件中的字符串,是包含匹配。
grep、awk、sed等命令支持正则表达式。
基础正则表达式:
01. "*" 前一个字符匹配0次或任意多次
"a*" 匹配所有内容,包括空格
"ab*" 匹配包含ab、ab123、ab123...等字符的字符串,"*"只对b起作用
"abc" 匹配包含abc、abc123、abc123...等字符的字符串
02. "." 匹配除了换行符外任意一个字符
"s..d" 匹配s和d之间有两个字符的
"s.*d" 匹配s和d之间有任意多字符
03. "^" 匹配行首, "$" 匹配行尾
"^a" 匹配以a开头的行
"$a" 匹配以a结尾的行
"^$" 匹配空白行
04.[]匹配中括号中指定的任意一个字符
"a[bcd]f" 匹配abf、acf、adf中的一个
"^[0-9]" 匹配数字开头的行
05.[^] 匹配空号中字符以外的一个字符
"^[^0-9]"
匹配以非数字开头的行
"^[^a-zA-Z]"
匹配非字母开头的行
06."\" 转义字符,使之后的一个特殊字符变为普通字符
"\*"
就是普通字符*
"\$$"
匹配以$的结尾的行
07."\{n\}"
匹配前面字符出现n次的字符串
"a\{4\}"
连续出现4个a的行
"[0-9]\{4\}"
连续出现4个数字的行,不一定完全一样的数字
"a\{2,5\}"
a{BANNED}最佳少出现2次,至多出现5次的行""
例:
"[0-9]\{4\}-[0-9]\{2\}-[0-9]\{2\}"
匹配格式为1990-02-10的日期
"[0-9]\{1,3\}.[0-9]\{1,3\}.[0-9]\{1,3\}.[0-9]\{1,3\}"
匹配格式为192.168.1.106的IP地址
字符截取命令:
01.cut命令:cut命令用于列提取,默认分隔符是tab键。
选项:-d 指定分隔符,-f 指定提取第几列
例:cut -d ":" -f1 /etc/passwd
为:为分隔符提取文件的{BANNED}中国第一列
grep "/bin/bash" /etc/passwd |grep -v root |cut -f1 -d ":"
列出系统中普通用户的用户名
02.awk命令
A:语法格式:awk '条件1{动作1}条件2{动作2}...' 文件
条件,一般使用关系表达式作为条件,如 a>10.
动作,awk一次读入一整行,默认以tab键或者空格为分隔符将一行分为多个字段,
表示为$1、$2、$3...其中$0表示文件名
例:
打印文件的第二列,其中的转义字符要加双引号。
awk '{printf $2 "\n"}' /etc/passwd
显示某分区磁盘使用量百分比
df -h |grep "/dev/sda1" |awk '{print $5}' | cut -d "%" -f1
B:BEGIN、END作为关系表达式,表示命令行开始时和结束时
例:
开始执行时FS指定分隔符
awk 'BEGIN{print "itpux:"}{print $1}' /etc/passwd
结束时打印一句话
awk 'END{print "itpux:"}{print $2}' /etc/passwd
C:格式化输出printf:
printf命令用于格式化输出,是echo命令的增强版
命令格式:printf '输出类型转义符' 输出内容
常用输出格式:
%ns:输出字符串;输出n位的字符串
%ni:输出整数:输出n位的整数
%m.nf:输出浮点数:m位整数和n位小数
print比printf更强的就是自动换行。
printf常用转义符:
\t
水平tab键
\v
垂直tab键
\n
换行
\r 回车,Enter键
\f
清除屏幕
\b
输出退格键
\a
输出警告声音
printf常用举例:
#printf %s abcdef
abcdef
#printf "%s\n" abc def
abc
def
sed命令:sed命令主要用来将数据进行选取、替换、删除、新增的命令
sed [选项] '动作' 文件名
选项:
-n:只会将sed处理的行输出,否则默认全篇输出
-e:允许进行多个动作
-i:sed修改默认是临时修改,
-i选项表示直接修改文件动作:
a:追加,在当前行后添加
c:行替换
i:在当前行前插入
d:删除指定行
p:打印输出指定行
s:字符串替换,格式:行范围s/旧字符串/新字符串/g
例:
sed -n '2p' /etc/passwd
打印输出第二行
sed -i '2,4d' /etc/passwd
删除2至4行
sed -i '2a ok' /etc/passwd
第二行追加内容
sed -i '3c ok' /etc/passwd
替换第3行
sed -i '3i ok' /etc/passwd
在第3行前插入
sed -i '2s/spool/spool2/g' /etc/passwd
第2行的spool替换为spool2
sed -ie 's/var/var2/g;s/sbin/sbin2/g' /etc/passwd
同时多个动作
sort命令:
01.sort命令用来排序
sort [选项] 文件名
选项:
-f:忽略大小写
-n:以数值型进行排序,默认是字符串排序
-r:反向排序
-t:指定分隔符,默认分隔符是tab键
-k n[,m]:指定排序的字段范围,n字段开始,m字段结束(可选),默认是到结尾
例:sort /etc/passwd 按首字母排序
wc命令:统计命令
wc [选项] 文件名
-l:只统计行数
-w:只统计单词数
-m:只统计字符数,包括换行符
例如: ps -ef|grep LOCAL=NO |wc -l
4.Linux Shell条件判断与流程控制
条件判断:
格式:test [选项] file 或者 [(空格)条件判断式(空格)]
01.按文件类型进行判断
选项:
-d:判断文件是否存在,且是目录文件时为真
-e:判断文件是否存在,存在时为真
-f:判断文件是否为真,且为普通文件时为真
-b:判断文件是否存在,且为块设备文件时为真
-c:判断文件是否存在,且为字符设备时为真
-L:判断文件是否存在,且为符号链接文件时为真
-p:判断文件是否存在,且为管道文件时为真
-s:判断文件是否为非空,非空时为真
-S:判断套接字文件是否存在,存在时为真
例:[-e filename] && echo yes || echo no
02.按文件权限进行判断
-r:拥有读权限时为真
-w:拥有写权限时为真
-x:拥有执行权限时为真
03.两个文件间比较
文件1 -nt 文件2
判断文件1是否比文件2新,若新则为真
文件1 -ot 文件2
判断文件1是否比文件2旧,若旧则为真
文件1 -ef 文件2
判断文件1iNode节点号是否和文件2相同(可用此判断硬链接)
04.连个整数间比较
整数1 -eq 整数2
判断是否相等
整数1 -ne 整数2
判断是否不相等
整数1 -gt 整数2
判断是否大于
整数1 -ge 整数2
判断是否大于等于
整数1 -lt 整数2
判断是否小于
整数1 -le 整数2
判断是否小于等于
05.字符串的判断
-z
判断字符串是否为空
-n
判断字符串是否为非空
字符串1 == 字符串2 判断是否相等
字符串1 != 字符串2 判断是否不等
例:[-z "$name"] $$ echo yes || echo no
06.多重条件判断
判断1 -a 判断2
逻辑与,1和2 都为真{BANNED}最佳终结果才为真
判断1 -o 判断2
逻辑或,1和2 有一个为真结果就为真
!判断1
逻辑非
07.举例:
两种判断格式:
test -e /root/install.log
[-d /root] && echo "yes" || echo "no"
{BANNED}中国第一个判断命令如果正确执行,则打印"yes",否则打印"no"
注意Linux中0表示命令成功; 1,表示命令失败
例子:
[root@localhost~]#ls install.log ...
[root@localhost~]#test -e /root/install.log
[root@localhost~]#echo $?
0
[root@localhost~]#test -e /root/install.log1
[root@localhost~]#echo $?
1
[root@localhost~]#test -e /root/install.log && echo yes || echo no
yes
[root@localhost~]#test -e /root/install.log1 && echo yes || echo no
no
其实上面时if的单分支语句,注意顺序不可以变化,如果no执行了那么yes也会出现,
毕竟正确执行了
流程控制:
if语句:提供条件测试。测试可以基于各种。例如文件的权限、长度、数值或字符串的
比较。这些测试返回值或者为真(0),或者为假(1).基于此结果,可以进行相关
操作。在讲到条件测试时已经涉及了一些测试语法。
01.单分支if语句
if[条件判断式];then
程序
fi
或者
if[条件判断式]
then
程序
fi
注意:中括号和条件判断式之间必须有空格
例1:判断当前用户是root
#!/bin/bash
if ["$USER"==root];then
echo "Login User is root"
fi
###################或者########################
#!/bin/bash
if ["$USER"==root]
then
echo "Login User is root"
fi
例2:判断分区空间使用率
#!/bin/bash
test=$(df -h |grep /dev/sda1 |awk '{print $5}' |cut -d "%" -f1)
if [$test -ge 10]
then
echo "sda1 is 10"
fi
02.双分支if语句
if [条件判断式];then
条件成立时,执行的程序
else
条件不成立时,执行的程序
fi
或者
if [条件判断式]
then
条件成立时,执行的程序
else
条件不成立时,执行的程序
fi
例1:输入一个文件,判断是否存在
#!/bin/bash
read -p "Please input a file:" file
if [-f $file];then
echo "File:$file exists!"
else
echo "File:$file not exists!"
fi
例2:判断apache服务是否启动了,如果没有启动,就代码启动
#!/bin/bash
test=$(ps aux|grep httpd|grep -v 'grep'|wc -l)
if[$test -gt 0];then
echo "$(date) httpd is running!"
else
echo "$(date) httpd isn't running,will be started!"
/etc/init.d/httpd start
fi
03.多分支if语句
if [条件判断式1];then
当条件判断式1成立时,执行程序1
elif [条件判断式2];then
当条件判断式2成立时,执行程序2
....省略更多条件....
else
当所有条件都不成立时,{BANNED}最佳后执行此程序
fi
04.多分支case语句
case $变量名 in
"值1")
如果变量的值等于值1,则执行程序1
;;
"值2")
如果变量的值等于值2,则执行程序2
;;
....省略其他分支....
*)
如果变量的值都不是以上的值,则执行此程序
;;
esac
例如: 判断用户输入
#!/bin/bash
read -p "please choose yes/no:" cmd
case $cmd in
"yes")
echo "Your choose is yes!"
;;
"no")
echo "Your choose is no!"
;;
*)
echo "Your choose is error!"
;;
esac
for循环
每次处理依次列表内信息,直至循环耗尽。
语法一:
for 变量名 in 值1 值2 值3 ...
do
程序
Done
语法二:
for ((初始值;循环控制条件;变量变化))
do
程序
done
例1:批量解压缩文件
#!/bin/bash
ls *.tar.gz > tar.log
for i in $(cat tar.log)
do
tar -zxf $i &>/dev/null
done
rm -rf tar.log
例2:1加到1000
#!/bin/bash
s=0
for((i=1;i<=1000;i=i+1))
do
s=$(($s+$i))
done
echo "$s"
例3:批量添加用户
echo "-----add 9 users-----"
for i in {1..9};do
username=itpux0$i
if useradd $username &> /dev/null;then
echo "$username" |passwd --stdin $username
if [$? -eq 0];then
echo "add $username successful"
else
echo "$username added,change password failure"
fi
else
echo "add $username failure"
fi
done
例4:批量删除普通用户
#!/bin/bash
for i in $(cat /etc/passwd |grep /bin/bash |grep -v root |cut -d ":" -f1)
do
userdel $i
done
while循环:
while循环当条件为真时,循环执行。
流控制语句得任何循环均可嵌套使用,例如可以在一个for循环中嵌入另一个for循环。
语法:
while [条件判断式]
do
程序
done
例:
#!/bin/bash
#
awk -F:'{print $1,$3,$7}' /etc/passwd >>passwd.txt
while read name id shell
do
echo "user name:$name"
echo "user uid:$id"
echo "user shell:$shell"
echo
done
注意:passwd.txt文件的列数一定要大于变量的个数,否则,会报错
until循环:
until循环直至条件为真,条件部分在循环末尾部分。
语法:是在条件不成立时执行
until [条件判断式]
do
程序
done
案例:
vi 1.sh
#!/bin/bash
echo "This example is for test.do"
echo "If you input [exit] then quit the system"
echo -n "please input:"
read EXIT
until [$EXIT ="exit"]
do
read EXIT
done
echo "OK!"
执行脚本:
chmod 775 1.sh
./1.sh
循环控制语句:
break命令不执行当前循环体内break下面的语句,从当前循环退出。
continue命令是程序在本循环体内忽略下面的语句,从循环头开始执行。
例1:脚本进入死循环直至用户输入数字大于5。要跳出这个循环,返回到shell提示符下,需要使用break命令。
#!/bin/bash
while:
do
echo -n "Input a number between 1 to 5:"
read aNum
case $aNum in
1|2|3|4|5) echo "Your number is $aNum"
;;
*) echo "You do not select a number between 1 to 5,game is over!"
break
;;
esac
done
例2:continue命令与break命令类似,只有一点差别,它不会跳出所有循环,仅仅跳出当前循环。
#!/bin/bash
while:
do
echo -n "Input a number between 1 to 5:"
read aNum
case $aNum in
1|2|3|4|5) echo "Your number is $aNum"
;;
*) echo "You do not select a number between 1 to 5,game is over!"
continue
echo "Game is over!"
;;
esac
done
******************************************************************