shell又称命令解释器,它能识别用户输入的各种命令,并传递给操作系统
它的作用类似于Windows操作系统中的命令行,但是,Shell的功能远比命令行强大的多;在UNIX或者localhost中,Shell既是用户交互的界面,也是控制系统的脚本语言
CentOS linux系统默认的shell为bash
shell | 相关 |
---|---|
Bourne Shell | 标识为sh,该Shell由Steve Bourne在贝尔实验室时编写。在许多Unix系统中,该Shell是root用户的默认的Shell。 |
Bourne-Again Shell | 标识为bash,该Shell由Brian Fox在1987年编写,是绝大多数linux发行版的默认的Shell。 |
Korn Shell | 标识为ksh,该Shell由贝尔实验室的David Korn在二十世纪八十年代早期编写。它完全向上兼容 Bourne Shell 并包含了C Shell 的很多特性。 |
C Shell | 标识为csh,该Shell由Bill Joy在BSD系统上开发。由于其语法类似于C语言,因此称为C Shell。 |
查看系统shell cat /etc/shells
查看系统默认shell echo $SHELL
查看系统的bash版本 bash --version
或 rpm -qa bash
检查bash是否安全
老版本的bash存在较为严重的安全信息,凭借漏洞,攻击者可能会接管计算机的整个系统
[root@zycentos7 ~]# env x='(){:;};echo be careful ' bash -c "echo this is a test"
this is a test
如果返回如下内容,则需要升级bash yum -y update bash
be careful
this ia a test
命令或程序语句不在命令行下执行,而是通过一个程序文件来执行,该程序文件就是脚本
语言 | 优点 |
---|---|
php语言 | 优势在于小型网站系统的开发 |
perl语言 | 优势在于开发较为复杂的运维工具软件、web界面的管理工具和web业务的开发(例如:跳板机、批量管理软件saltstack等) |
python语言 | 上层语言,类似于Java,go等编程语言(cmdb自动化运维平台,openstack) |
shell语言 | 优势在于处理偏操作系统底层的业务,使用shell更符合liunx运维简单、易用、高效的原则 |
shell脚本运行时首先查找系统环境变量ENV,该变量制定了环境文件(加载顺序通常是/etc/profile 、~/.bash_profile 、~/.bashrc 、/etc/bashrc等),在加载了以上环境变量文件后,shell就开始执行shell脚本中的内容
sh test.sh
或 bash test.sh
./test.sh
或 path/test.sh
source test.sh
或 .test.sh
sh < test.sh
或 cat test.sh | sh :
[root@zycentos7 ~]# cat a.sh
userdir=`pwd`
[root@zycentos7 ~]# sh a.sh
[root@zycentos7 ~]# echo $userdir
[root@zycentos7 ~]# source a.sh
[root@zycentos7 ~]# echo $userdir
/root
#!bin/bash
其他#行表示注释可以在创建变量的shell以及派生出来的任意子进程shell中使用,又可分为:自定义环境变量和bash内的环境变量
环境变量的名字均采用大写形式
只能在创建他们的shell函数或shell脚本中使用
set 输出所有变量
env 输出全局变量
declare 输出所有变量、函数、和已经导出的变量
export NAME=value
[root@zycentos7 ~]# declare -x JOB=linux
[root@zycentos7 ~]# declare|grep JOB
JOB=linux
_=JOB=linux
[root@zycentos7 ~]# declare|grep JOB
JOB=linux
[root@zycentos7 ~]# a="BeiJing TIME:`date`" ;反引号
[root@zycentos7 ~]# echo $a
BeiJing TIME:Sun Dec 8 15:29:53 CST 2019
[root@zycentos7 ~]# a='BeiJing TIME:"date"' ;双引号,弱引用
[root@zycentos7 ~]# echo $a
BeiJing TIME:"date"
[root@zycentos7 ~]# a='BeiJing TIME:'date'' ;单引号,强引用,所见即所得
[root@zycentos7 ~]# echo $a
BeiJing TIME:`date`
[root@zycentos7 ~]# CMD=$(pwd)
[root@zycentos7 ~]# echo $CMD
/root
~.bash_profile
.bashrc
/etc/profile
/etc/profile.d/
/etc/bashrc
linux系统bash加载环境变量的过程
系统运行shell的方式
(1)通过系统用户登录后默认运行的shell
(2)非交互式运行Shell
(3)执行脚本运行非交互式shell
[root@zycentos7 ~]# echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin
Centos 6 grub-md5-cryp
Centos 7 grub2-mkpasswd-pbkdf2
$ Number 第Number个参数
$# 参数个数
echo输出自然数
[root@zycentos7 ~]# echo {0..10}
0 1 2 3 4 5 6 7 8 9 10
eval会对后面的cmdLine进行两遍扫描,如果在第一遍扫面后cmdLine是一个普通命令,则执行此命令;如果cmdLine中含有变量的间接引用,则保证简介引用的语义
eval生成随机数
[root@zycentos7 ~]# cat test.sh
END=5
for i in `eval echo {1..$END}`
do
echo $i
done
[root@zycentos7 ~]# sh test.sh
1
2
3
4
5
测试eval
[root@zycentos7 ~]# set 11 22 33 44
[root@zycentos7 ~]# echo $4
44
[root@zycentos7 ~]# echo $#
4
[root@zycentos7 ~]# echo "$$#"
7107#
[root@zycentos7 ~]# echo "\$$#"
$4
[root@zycentos7 ~]# eval echo "\$$#"
44
seq [选项]... 尾数
seq [选项]... 首数 尾数
seq [选项]... 首数 增量 尾数
seq -w 在列前添加0,使得宽度相同
[root@zycentos7 ~]# seq -w 98 100
098
099
100
seq -f 使用printf 样式的浮点格式
-f"%#g"(补空格)
-f"%0#g"(补0)
[root@zycentos7 ~]# seq -f"%4g" 8 12
8
9
10
11
12
[root@zycentos7 ~]# seq -f"%04g" 8 12
0008
0009
0010
0011
0012
-s 指定分隔符(默认使用\n)换行\n无效
[root@zycentos7 ~]# seq -s" " -f"str%02g" 9 11
str09 str10 str11
[root@zycentos7 ~]# seq -s"`echo -e "\t"`" -f"str%02g" 9 11
str09 str10 str11
(1)通过内部系统变量($RANDOM) echo $RANDOM
(2)使用awk的随机函数 awk 'BEGIN{srand();print rand()*1000000}'
(3)openssl rand产生随机数 openssl rand -base64 8
1.八位字母和数字的组合
openssl rand -base64 8|md5sum|cut -c 1-8
2.八位数字
openssl rand -base64 8|cksum|cut -c 1-8
(4)通过时间获得随机数(date)
1.生成19位数字
date +%s%N #
2.取八位数字
date +%s%N|cut -c 6-13
13578053
3.八位字母和数字的组合
date +%s%N|md5sum|head -c 8
(5)通过系统内唯一数据生成随机数
1./dev/random存储系统当前运行的环境的实时数据,可以看作系统某时候的唯一值数据,提供优质随机数
2./dev/urandom是非阻塞的随机数产生器,读取时不会产生阻塞,速度更快、安全性较差的随机数发生器
1.生成数字和字母混合的随机字符串
cat /dev/urandom|head -n 10|md5sum|head -c 10
【dc32c5047f】
2.生成全字符的随机字符串
cat /dev/urandom|strings -n 8|head -n 1
【}pFYi%%D~】
3.生成数字加字母的随机字符串,其中 strings -n设置字符串的字符数,head -n设置输出的行数
cat /dev/urandom|sed -e 's#[^a-zA-Z0-9]##g'|strings -n 8|head -n 1
【aPdKtMod】
4.生成全数字的随机字符串
head -200 /dev/urandom|cksum|cut -d " " -f1
【1182233652】
(6)读取Linux的uuid码
UUID码全称是通用唯一识别码 (Universally Unique Identifier, UUID),UUID格式是:包含32个16进制数字,以“-”连接号分为五段,形式为8-4-4-4-12的32个字符,linux的uuid码由内核提供,在/proc/sys/kernel/random/uuid文件内。
cat/proc/sys/kernel/random/uuid
每次获取到的数据都会不同
1.获取不同的随机整数
cat /proc/sys/kernel/random/uuid |cksum|cut -f1 -d " " #
【3838247832】
2.数字加字母的随机数
cat /proc/sys/kernel/random/uuid |md5sum|cut -c 1-8 #
【6092539b】
(7)从元素池中随机抽取
pool=(a b c d e f g h i j k l m n o p q r s t 1 2 3 4 5 6 7 8 9 10)
num=KaTeX parse error: Expected '}', got '#' at position 2: {#̲pool[*]} result…{pool[$((RANDOM%num))]}
用于生成一段特定长度的有数字和字母组成的字符串,字符串中元素来自自定义的池子
[root@zycentos7 ~]# cat seqeand.sh
length=8
i=1
seq=(0 1 2 3 4 5 6 7 8 9 a b c d e f g h i j k l m n o p q r s t u v w x y z A B C D E F G H I J K L M N O P Q R S T U V W X Y Z)
num_seq=${#seq[@]}
while [ "$i" -le "$length" ]
do
seqrand[$i]=${seq[$((RANDOM%num_seq))]}
let "i=i+1"
done
echo "The random string is:"
for j in ${seqrand[@]}
do
echo -n $j
done
echo
[root@zycentos7 ~]# sh seqeand.sh
The random string is:
j2dZnA5r
[root@zycentos7 ~]# cat /proc/sys/kernel/random/uuid
75052f89-9b32-4dcd-8deb-146a616be19e
(1)echo "00:60:2F$(dd bs=1 count=3 if=/dev/random 2>/dev/null |hexdump -v -e '/1 ":%02X"')"
(2)echo "$(hexdump -n3 -e'/3 "00:60:2F" 3/1 ":%02X"' /dev/random)"
(3)printf '00:60:2F:%02X:%02X:%02X\n' $[RANDOM%256] $[RANDOM%256]
(4)echo 00:60:2f:`openssl rand -hex 3 | sed 's/\(..\)/\1:/g; s/.$//'`
; 不具备逻辑判断
&& 前一个命令执行成功才继续执行下一个命令
|| 前一个命令执行的结果不影响下一个命令
command & 后台执行
command &>/dev/null 混合重定向(标准输出1,错误输出2)
command1 && command2 命令排序,逻辑判断
位置变量 | 作用说明 |
---|---|
$0 | 获取当前执行的Shell脚本的文件名,如果执行脚本包含了路径,那么就包括脚本路径 |
$n | 获取当前执行的Shell脚本的第n个参数值,n=1…9,n大于9用大括号括起来,例如${10},接的参数以空格隔开 |
$# | 获取当前执行的Shell脚本后面接的参数的总个数 |
$*或$@ | 获取当前Shell脚本所有传参的参数 |
“$*” | 将所有的参数视为单个字符串,相当于"$1 $2 $3" |
“$@” | 将所有的参数视为不同的独立字符串,相当于"$1" “$2” “$3”…" |
$@和"$@“等价,$*和”$*" 不等价
"$@"是将多参数传递给其他程序的最佳方式,因为它会保留所有的内嵌在每个参数里的任何空白
[root@zycentos7 ~]# dirname /root/test/test.sh
/root/test
[root@zycentos7 ~]# basename /root/test/test.sh
test.sh
"$*“和”$@"的区别测试
[root@zycentos7 ~]# set -- This "is a" test
[root@zycentos7 ~]# for i in "$@";do echo $i;done
This
is a
test
[root@zycentos7 ~]# for i in "$*";do echo $i;done
This is a test
$*和"$*"的区别
$* 参数单独列出
"$*" 所有参数当成一个整体
n=0
for i in $*
do
echo $i
let n++
done
echo $n
echo "---------------------"
for j in "$@"
do
echo $j
done
位置变量 | 作用说明 |
---|---|
$? | 获取执行上一个指令的执行状态返回值(0成功,非0为失败) |
$$ | 获取当前执行的Shell脚本的进程号(PID) |
$! | 获取上一个在后台工作的进程的进程号(PID) |
$_ | 获取在此之前执行的命令或脚本的最后一个参数 |
[root@zycentos7 ~]# cat c.sh
read -p "please input your number:" num
if [ 5 -eq $num ]
then
echo "$num"
exit 10
elif [ 6 -eq $num ]
then
echo "$num"
exit 20
else
echo "$num"
exit 30
fi
[root@zycentos7 ~]# sh c.sh
please input your number:4
4
[root@zycentos7 ~]# echo $?
30
[root@zycentos7 ~]# ls -l
[root@zycentos7 ~]# echo $_
-l
在企业场景下,“$?”返回值的用法如下:
练习 【$$的企业级应用】实现系统中多次执行某一个脚本后的进程只有一个
说明:有时执行定时任务脚本的频率比较快,并不知道上一个脚本是否真的执行完毕,但是,业务要求同一时刻只能有一个同样的脚本在运行,此时就可以利用$$获取上一次运行的脚本进程号,当程序重新运行时,根据获得的进程号,清理掉上一次的进程,运行新的脚本命令
内部命令:echo ,eval,exec,export,read,shift
echo参数选项 | 说明 |
---|---|
-n | 不换行输出内容 |
-e | 解析转义字符 |
转义字符 | 说明 |
---|---|
\n | 换行 |
\r | 回车 |
\t | 制表符(tab) |
\b | 退格 |
\v | 纵向制表符 |
exec命令能够在不创建新的子进程的前提下,转去执行指定的命令,当指定
的命令执行完毕后,该进程( 也就是最初的Shell)就终止了
[zhao@zycentos7 ~]$ exec date ;root用户执行会退出登录
Wed Dec 18 08:55:46 CST 2019
exec < /etc/passwd
while read line
do
echo $line
done
当使用exec打开文件后,read 命令每次都会将文件指针移动到文件的下一行进行读取,直到文件末尾,利用这个可以实现处理文件内容
read -p
shift 语句会按如下方式重新命名所有的位置参数变量
即$2成为$1、$3成为$2等,以此类推
在程序中每使用一次shift 语句,都会使所有的位置参数依次向左移动一个位置,并使位置参数$#减1,直到减到0为止
应用场景 当我们写Shell希望像命令行的命令通过参数控制不同的功能时,就会先传一个类似-c的参数,然后再接内容
退出Shell程序,在exit之后可以有选择地指定一个数位作为返回状态
表达式 | 说明 |
---|---|
${parameter} | 返回字符串的内容 |
${#parameter} | 统计字符串长度 |
${parameter:offset} | 从第offset个字符开始输出 |
${parameter:offset:length} | 从第offset个字符开始输出length个字符 |
${parameter#word} | 从开头开始删除最短匹配的字符串 |
${parameter##word} | 从开头开始删除最长匹配的字符串 |
${parameter%word} | 从结尾开始删除最短匹配的字符串 |
${parameter%%word} | 从结尾开始删除最长匹配的字符串 |
${parameter/pattern/string} | 使用string代替第一个匹配的pattern |
${parameter//pattern/string} | 使用string代替所有匹配的pattern |
实例1 统计字符串a的长度
echo ${#a} ;速度最快
expr length "$a"
echo $a|wc -L
echo $a|awk '{print length($0)}'
实例2 批量修改文件名:将testXX.txt修改为ybcXX.txt
[root@zycentos7 ~]# touch file/test{01..20}.txt
[root@zycentos7 ~]# cat mv.sh
for i in `ls file`
do
echo $i
mv file/$i file/${i/test/ybc}
done
[root@zycentos7 ~]# sh mv.sh
实例3 打印下面语句中字符数小于6的单词
I am oldboy linux,welcome to our training.
[root@zycentos7 ~]# cat cut.sh
for i in `cat a.txt`
do
#echo ${#i}
if [ ${#i} -lt 6 ]
then
echo $i
fi
done
[root@zycentos7 ~]# sh cut.sh
I
am
to
our
表达式 | 说明 |
---|---|
{parameter:-word} | parameter有值输出值,无则输出word |
{parameter:=word} | parameter有值输出值,无则输出word,并将word赋值给parameter |
{parameter:?word} | parameter值为空,word作为标准错误输出 |
{parameter:+word} | parameter值不为空,输出时word替换其值 |
实例 删除7天的过期备份数据
DIR_BACK=backup
find ${DIR_BACK:-/backup} -type f -mtime +7 -exec rm -rf {} \;
防止忘记定义DIR_BACK变量而导致异常
+、-、、/、%、++、–、&&、||、!、**(幂运算)
比较符号:==、!=、=(对于字符串表示相当于)
赋值符号:=、+=、-=、=、/=、%=
运算操作符与运算命令 | 意义 |
---|---|
(()) | 用于整数运算的常用运算符,效率很高 |
let | 用于整数运算,类似于“(())’ |
expr | 可用于整数运算,但还有很多其他的额外功能 |
bc | Linux下的一个计算器程序(适合整数及小数运算) |
$[] | 用于整数运算 |
awk | awk既可以用于整数运算,也可以用于小数运算 |
declare | 定义变量值和属性,-i 参数可以用于定义整形变量,做运算 |
语法
let 赋值表达式
let赋值表达式的功能等同于“((赋值表达式))”
范例5-12:监控Web服务状态,如果访问两次均失败,则报警(let 应用案例)。
要注意,在使用expr时:
expr命令用途:
(1)整数运算
(2)字符串匹配
(3)字符串长度计算
双小括号 “(())” 的操作方法
运算操作符与运算命令 | 意义 |
---|---|
((i=i+1)) | 此种书写方法为运算后赋值法,即将i+1的运算结果赋值给变量i,不能用“echo ((i=i+1))”的形式输出表达式的值,但可以用echo $((i=i+1))输出其值 |
i=$((i+1)) | 可以在“(())” 前加$符,表示将表达式运算后赋值给i |
((8>7&&5==5)) | 可以进行比较操作,还可以加入逻辑与和逻辑或,用于条件判断 |
echo $((2+1)) | 需要直接输出运算表达式的运算结果时,可以在“(O)" 前加$符 |
实例1 判断一个变量值或字符串是否是整数
read -p "num1:" num1
read -p "num1:" num2
expr $num1 + 1 >/dev/null 2>&1
if [ $? -ne 0 ]
then
echo "请您输入一个正确的整数.."
exit
fi
expr $num2 + 1 >/dev/null 2>&1
if [ $? -ne 0 ]
then
echo "请您输入一个正确的整数.."
exit
fi
echo "$num1 + $num2 = `expr $num1 + $num2`"
echo "$num1 - $num2 = `expr $num1 - $num2`"
echo "$num1 * $num2 = `expr $num1 \* $num2`"
echo "$num1 / $num2 = `expr $num1 / $num2`"
实现原理:利用以expr作运算时变量或者字符串必须是整数的规则,把一个变量或字符串和一个已知的整数(非0)相加,看命令返回值是否为0,为0,则认为做加法的变量或字符串为整数,否则就不是
实例2 判断文件扩展名是否符合要求
if expr "$1" : ".*\.pub" >/dev/null 2>&1
then
echo "真.."
else
echo "假.."
fi
常用语法
条件测试语法 | 说明 |
---|---|
test <测试表达式> | test 命令和“<测试表达式>”之间至少有一个空格 |
[ <测试表达式> ] | []的边界和内容之间至少有一个空格 |
[[ <测试表达式> ]] | [[]] 的边界和内容之间至少有一个空格 |
((< 测试表达式>)) | 一般用于if语句,(()) 两端不需要有空格 |
1.在[]中可以使用通配符等进行模式匹配
2.&&、|、>、<等操作符可以应用于[[]]中,但不能应用于[]中,在[]中一般用-a、-o、-gt (用于整数)、-It (用于整数)代替上述操作符
3.对于整数的关系运算,也可以使用Shell 的算术运算符(())
文件测试表达式
常用文件测试操作符 | 说明 |
---|---|
-d | 文件存在且为目录则为真 |
-f | 文件存在且为普通文件则为真 |
-e | 文件存在则为真,注意区别于“-f”, -e不辨别是目录还是文件 |
-r | 文件存在且可读则为真 |
-s | 文件存在且文件大小不为0则为真 |
-w | 文件存在且可写则为真 |
-x | 文件存在且可执行则为真 |
-L | 文件存在且为链接文件则为真 |
fl -nt f2 | 文件fl比文件f2新则为真(修改时间)newer than |
fl -otf2 | 文件fl比文件f2旧则为真(修改时间)older than |
字符串测试表达式
常用字符串测试操作符 | 说明 |
---|---|
-n “字符串” | 字符串的长度不为0则为真 no zero |
-z “字符串” | 字符串的长度为0则为真 zero |
"串1" = "串2",可使用"=="代替"="
"串1" != "串2",不可使用"!=="代替"="
对于字符串的测试,一定要将字符串加双引号之后再进行比较,如[ -n “$myvar” ],特别是使用[]的场景,字符串比较时若等号两端没有空格,则会导致判断出现逻辑错误
整数二元比较操作符
if条件命令选项 | 含义 |
---|---|
-eq | 比较两个参数是否相等(例如,if [ 2 –eq 5 ]) |
-ne | 比较两个参数是否不相等 |
-lt | 参数1是否小于参数2 |
-le | 参数1是否小于等于参数2 |
-gt | 参数1是否大于参数2 |
-ge | 参数1是否大于等于参数2 |
逻辑操作符
if条件命令选项 | 含义 |
---|---|
-a | 与,两端都为真,结果为真 |
-o | 或,两端有一个为真,结果为真 |
! | 两端相反,结果为真 |
练习1 条件测试的方法
如果文件存在,输出true,否则输出false
test -f file && echo true || echo false
测试字符串是否为0
[root@zycentos7 ~]# test -z "oldboy" && echo 1 || echo 0
0
[root@zycentos7 ~]# test -z "" && echo 1 || echo 0
1
如果文件存在,输出1,否则输出0
[ -f file ] && echo 1 || echo 0
如果文件存在,输出y,否则输出n
[[ -f file ]] && echo y || echo n
三种方法的比较
[[]] 与其他两种测试表达式的其别在于,其内可以使用通配符,并且&& || > <等操作符号可以应用与其内,但是不能用于[]中,在[]中一般使用 -a -o -gt(用于整数)、-lt等操作符
练习2 文件测表达式
测试shell变量
[root@zycentos7 ~]# file1=/etc/services
[root@zycentos7 ~]# [ -f "$file1" ] && echo y || echo n
y
练习3 字符串测试表达式
[ -n "abc" ] && echo 1 || echo 0
单分支结构
if <条件表达式>
then
指令
fi
双分支结构
if <条件表达式>
then
指令集1
else
指令集2
fi
多分支结构
if <条件表达式1>
then
指令1
elif <条件表达式2>
then
指令2
else
指令3
fi
练习 猜一猜
while true
do
read -p "input the number you think:" num
if [ $num -gt 58 ]
then
echo "猜大了"
elif [ $num -lt 58 ]
then
echo "猜小了"
else
echo "恭喜,猜对了"
exit 10
fi
done
case "变量" in
值1)
指令1...
;;
值2)
指令2...
;;
*)
指令3...
esac
企业案例 rsync服务的启动脚本
case $1 in
start)
rsync --daemon
#echo "start"
;;
stop)
pkill rsync
#echo "stop"
;;
restart)
pkill rsync
rsync --daemon
#echo "restart"
;;
*)
echo "User:`basename $0` start | stop | restart."
esac
[root@zycentos7 ~]# mv RSYNC.sh /usr/local/bin/RSYNC
[root@zycentos7 ~]# chmod a+x /usr/local/bin/RSYNC
[root@zycentos7 ~]# ll /usr/local/bin/RSYNC
-rwxr-xr-x. 1 root root 441 Dec 15 04:38 /usr/local/bin/RSYNC
[root@zycentos7 ~]# RSYNC start
给输出的字符串加颜色
echo -e "\033[32m 字符串 \033[0m"
033[#m中的#值 | 颜色 |
---|---|
30 | 黑 |
31 | 红 |
32 | 绿 |
33 | 棕 |
34 | 蓝 |
35 | 洋红 |
36 | 蓝绿 |
37 | 白 |
给输出的字符串加背景颜色
echo -e "\033[40;32m 字符串 \033[0m"
033[#;中的#值 | 颜色 |
---|---|
40 | 黑 |
41 | 红 |
42 | 绿 |
33 | 棕 |
44 | 蓝 |
45 | 洋红 |
46 | 蓝绿 |
47 | 白 |
让输出的字符串闪烁
echo -e "\033[05;37m 字符串 \033[0m"
推荐使用 通过定义变量的方式给字体加颜色
RED_COLOR='\E[1;31m'
GREEN_COLOR='\E[1;32m'
YELLOW_COLOR='\E[1;33m'
BLUE_COLOR='\E[1;34m'
PINK='\E[1;35m'
RES='\E[0m'
echo -e "${RED_COLOR}======red color======${RES}"
echo -e "${YELLOW_COLOR}======yellow color======${RES}"
echo -e "${BLUE_COLOR}======blue color======${RES}"
echo -e "${GREEN_COLOR}======green color======${RES}"
echo -e "${PINK}======pink color======${RES}"
while <条件表达式>
do
指令...
done
util <条件表达式>
do
指令...
done
for 变量名 in 变量取值列表
do
指令...
done
c风格
for ((exp1;exp2;exp3))
do
指令...
done
练习 修改for循环默认的分隔符(空格)为换行
IFS_old=$IFS
IFS=$'\n'
for i in `cat /etc/passwd`
do
echo $i
done
IFS=$IFS_old
条件与循环控制及程序返回值命令知识表
命令 | 说明 |
---|---|
break n | 省略n表示跳出整个循环,n表示跳出循环的层数 |
continue n | 省略n表示跳过本次循环,忽略本次循环的剩余代码,进人循环的下一次循环,n表示退到第n层继续循环 |
exit n | 退出当前Shell程序,n为上一次程序执行的状态返回值,n可以省略($?) |
return n | 用于在函数里作为函数的返回值,以判断函数执行是否正确($?) |
练习 输出九九乘法表
for((i=1;i<=9;i++))
do
for((j=1;j<=i;j++))
do
echo -ne "$i*$j=$(($i*$j))\t"
done
echo ""
done
数组名[下标]=变量值
[root@zycentos7 ~]# array[0]=pear
[root@zycentos7 ~]# array[1]=apple
[root@zycentos7 ~]# echo ${array} ${array[1]}
pear apple
passwd=(`cat /etc/passwd`) ;将该文件中的每一个行作为一个元数赋值给数组passwd
array6=(1 2 3 4 5 6 "linux shell" [20]=ansinble) ;一次赋多个值,并指定其中某些值
array=(yi bochen) ;数组以空格符分隔各个数组元素
array=("yi bochen") ;数组元素值中含有空格,加""
path=($PATH $SHELL)
echo ${#colors[@]}
echo ${#colors[*]}
echo ${#colors[1]}
${数组名[下标]}
${数组名[@]:1} ;从下标为1开始打印全部
${数组名[@]:1:2} ;从下标为1开始打印2个
直接输出数组所有元素
echo ${path[@]}
按数组元素取值,可以不连续取值
for var in ${colors[@]};do echo $var;done
按数组下标(索引)取值,只能连续取值
for((i=0;i<${#colors[@]};i++));do echo ${colors[i]};done
unset array[2] ;删除数组中的某个元素
unset array ;删除整个数组
declare -a filename[1]=Linux
echo ${filename[@]:1} ;从下标为1开始打印全部
echo ${filename[@]:1:2} ;从下标为1开始打印2个
练习1 标准输入保存到数组里
读入标准输入
(1) $1 $2
(2) read -p “” num
(3) cat << EOF
EOF
i=0
while true
do
read -p "" num
array[$i]=$num
echo ${array[@]}
let i++
done
练习2 字符串保存到数组里
加空格保存
使用空格对字符进行分隔
str=`echo $str|sed ‘s/./& /g’`
chars="abcde"
chars=`echo $chars|sed 's/./& /g'`
j=0
for i in $chars
do
array[$j]=$i
let j++
echo ${array[@]}
done
将字符逐个取出
chars="abcd"
for((n=0;n<${#chars};n++))
do
array[$n]=${chars:$n:1}
echo ${array[@]}
done
练习3 将数组里的数值分别乘以8并打印
array=(1 2 3 4 5)
j=0
for i in ${array[@]}
do
array[$j]=$(($i*8))
let j++
done
echo ${array[@]}
函数是完成特定功能的代码片段(块)
在shell中定义函数可以使用代码模块化,便于复用代码,函数必须先定义才可以使用
格式1
function 函数名( )
{
指令… }
格式2
函数名()
{
指令… }
格式3
function 函数名
{
指令… }
函数名
函数名 参数1 参数2
练习1 写一个脚本,判定192.168.232.123-192.168.232.126之间的主机哪些在线
要求:
1、使用函数来实现一台主机的判定过程
2、在主程序中来调用此函数判定指定范围内的所有主机的在线情况
PING(){
for i in `seq 123 126`
do
if ping -c 1 -w 1 192.168.232.$i &>/dev/null 2>&1
then
echo "192.168.232.$i is Tong"
else
echo "192.168.232.$i is NOT Tong"
fi
done
}
PING
PING(){
if ping -c 1 -W 1 $1 &> /dev/null
then
return 0
else
return 1
fi
}
for i in {123..126}
do
PING 192.168.232.$i
if [ $? -eq 0 ]
then
echo "192.168.232.$i is up."
else
echo "192.168.232.$i is down."
fi
done
PING(){
for i in `seq $1 $2`
do
ping -c 1 $3$i >/dev/null 2>&1
if [ $? -eq 0 ]
then
echo "$3$i Tong.."
else
echo "$3$i Not Tong.."
fi
done
}
PING $1 $2 "192.168.232."
[root@zycentos7 ~]# sh ping.sh 123 126
192.168.232.123 Not Tong..
192.168.232.124 Not Tong..
192.168.232.125 Tong..
192.168.232.126 Not Tong..
练习2 写一个脚本,使用函数完成
要求
1、函数能够接受一个参数,参数为用户名
判断一个用户是否存在,如果存在,就返回此用户的shell和UID,并返回正常状态值;如果不存在,就说此用户不存在,并返回错误状态值
2、在主程序中调用函数
USER_CHECK(){
if id $1 >/dev/null 2>&1
then
grep "^$1:" /etc/passwd | cut -d: -f 3,7
n=0
else
echo "no"
n=1
fi
return $n
}
while true
do
read -p "username[q|Q,exit]:" username
if [[ $username == "" ]]
then
echo "root"
elif [[ $username == "q" || $username == "Q" ]]
then
exit
else
USER_CHECK $username
if [ $? -eq 0 ]
then
echo "状态值:0 true"
else
echo "状态值:1 false"
fi
fi
done
用法 | 说明 |
---|---|
sh while1.sh & | 把脚本whilel .sh放到后台执行(在后台运行脚本时常用的方法) |
ctl+c | 停止执行当前脚本或任务 |
ctl+z | 暂停执行当前脚本或任务 |
bg | 把当前脚本或任务放到后台执行,background |
fg | 把当前脚本或任务放到前台执行,如果有多个任务,可以使用fg加任务编号调出对应的脚本任务,如fg2,是指调出第二个脚本任务,frontground |
jobs | 查看当前执行的脚本或任务 |
kill | 关闭执行的脚本任务,即以“kill %任务编号”的形式关闭脚本,这个任务编号,可以通过jobs来获得 |
killall 或 pkill | 杀掉进程 |
ps | 查看进程 |
pstree | 显示进程状态树 |
top | 显示进程 |
renice | 改变优先权 |
nohup | 用户退出系统之后继续工作 |
pgrep | 查找匹配条件的进程 |
strace | 跟踪一个进程的系统调用情况 |
ltrace | 跟踪进程调用库函数的情况 |
练习1 用户批量管理工具(增删改查)
#定义变量
passwd="123456"
read_username="read -p "请输入用户名:" username"
read_num1="read -p "起始位置:" num1"
read_num2="read -p "终止位置:" num2"
#判断用户是否存在
CHECK_USER(){
id $username$i >/dev/null 2>&1
if [ $? -eq 0 ]
then
n=0
else
n=1
fi
return $n
}
#创建用户
CREATE_USER(){
#read -p "请输入用户名" username
#read -p "请输入用户名" num1
#read -p "请输入用户名" num2
useradd $username$i
echo "$passwd" |passwd --stdin $username$i >/dev/null 2>&1
}
#实现完整的用户创建功能
CREATE_USER_FULL(){
$read_username
$read_num1
$read_num2
#read -p "请输入用户名" username
#read -p "起始位置" num1
#read -p "终止位置" num2
for i in `seq -f "%02g" $num1 $num2`
do
CHECK_USER
if [ $? -eq 1 ]
then
CREATE_USER
else
echo "$username$i 已存在"
fi
done
}
#实现函数查看功能
SCAN_USER_LIST(){
array=`awk -F: '$3>=1000 {print $1}' /etc/passwd`
echo ${array[@]}
}
#修改用户密码
UPDATE_PASSWD(){
echo "$1" |passwd --stdin $username$i >/dev/null 2>&1
}
#实现批量修改用户密码
UPDATE_PASSWD_FULL(){
$read_username
$read_num1
$read_num2
#read -p "请输入用户名" username
#read -p "起始位置" num1
#read -p "终止位置" num2
read -p "请输入密码:" passwd
for i in `seq -f "%02g" $num1 $num2`
do
UPDATE_PASSWD $passwd
done
}
#实现批量删除用户
DELETE_USER_FULL(){
$read_username
$read_num1
$read_num2
#read -p "请输入用户名" username
#read -p "起始位置" num1
#read -p "终止位置" num2
for i in `seq -f "%02g" $num1 $num2`
do
userdel -r $username$i
done
}
while true
do
cat << EOF
--------------------菜单----------------------
+ 1.创建用户 +
+ 2.修改用户密码 +
+ 3.删除用户 +
+ 4.查看用户 +
+ 5.退出 +
----------------------------------------------
EOF
read -p "请输入菜单号(1-5):" num
case $num in
1)
CREATE_USER_FULL
;;
2)
UPDATE_PASSWD_FULL
;;
3)
DELETE_USER_FULL
;;
4)
SCAN_USER_LIST
;;
5)
exit
;;
*)
echo "请输入正确的菜单号..."
esac
done
练习2 获取随机字符串或数字
(1)获取随机8位字符串
(2)获取随机8位数字
length=8
i=1
seq=(0 1 2 3 4 5 6 7 8 9 a b c d e f g h i j k l m n o p q r s t u v w x y z A B C D E F G H I J K L M N O P Q R S T U V W X Y Z)
num_seq=${#seq[@]}
while [ "$i" -le "$length" ]
do
seqrand[$i]=${seq[$((RANDOM%num_seq))]}
let "i=i+1"
done
echo "The random string is:"
for j in ${seqrand[@]}
do
echo -n $j
done
[root@zycentos7 ~]# uptime|awk -F":|," '{print "1分钟平均负载:",$7"\n5分钟平均 负载:"$8"\n15分钟平均负载:"$9}'
1分钟平均负载: 0.00
5分钟平均负载: 0.01
15分钟平均负载: 0.05