一、for循环
for 变量名 in 列表;do
循环体
done
列表生成方式:
(1) 直接给出列表
(2) 整数列表:
(a) {start..end}
(b) $(seq [start [step]] end)
(3) 返回列表的命令
$(COMMAND)
(4) 使用glob,如:*.sh
(5) 变量引用;
$@, $*
例1:
[root@centos6 data]#for i in /data/*.sh;do echo the filename is $i;done
the filename is /data/67_createuser.sh
the filename is /data/checkint.sh
the filename is /data/createuser.sh
the filename is /data/filetype.sh
the filename is /data/if.sh
例2:求100以内的偶数和
#!/bin/bash
#
declare -i sum=0
for i in `seq 2 2 100`;do
let sum+=i
done
echo sum=$sum
例3:脚本内多行重定向写法
for i in {1..10};do
cat >> f1 <<-EOF
aa
bb
EOF
done
EOF前加上-
例4:创建10个用户,分别为user1到user10,密码分别为12345
#!/bin/bash
#
for i in user{1..10};do
if id $i &>/dev/null;then
echo “$i is exist”
else
useradd $i
echo “$i has created”
echo 12345 |passwd –stdin $i &>/dev/null
fi
done
例5:扫描某个网段的所有主机,在线显示up,不在线显示down,把在线的主机ip保存到文件中hostup.list
#!/bin/bash
#
net=192.168.67
for i in {1..254};do
{ if ping -c1 -w1 $net.$i &>/dev/null;then
echo “$net.$i is up”
echo $net.$i >> /data/hostup.list
else
echo “$net.$i is down”
fi } &
done
wait
加上{ }加快运行速度,多个程序并行执行,wait表示执行结束自动弹出
二、let命令中 i++与++i 的区别
i++:
[root@centos6 data]#i=0
[root@centos6 data]#let i++
[root@centos6 data]#echo $?
1
++i:
[root@centos6 data]#i=0
[root@centos6 data]#let ++i
[root@centos6 data]#echo $?
0
三、eval命令
[root@centos6 data]#n=3;for i in `eval echo {1..$n}`;do echo num is $i ;done
num is 1
num is 2
num is 3
eval命令会先引用变量$n,让后在执行echo命令
四、for循环嵌套
for i in {1..10};do
for i in {1..10};do
…
done
done
例1:打印矩形
length=$1
width=$2
for i in `seq 1 $length`;do
for j in `seq 1 $width`;do
color=$[RANDOM%7+31]
bk=$[RANDOM%7+41]
echo -e “\e[1;5;${bk};${color}m*\e[0m\c”
done
echo
done
例2:打印9*9乘法表
for i in {1..9};do
for j in `seq 1 $i`;do
sum=$[i*j]
echo -e “${j}*${i}=${sum}\t\c”
done
echo
done
例3:打印国际象棋
for i in {1..8};do
for k in {1..2};do
if [ $[i%2] -eq 0 ];then
for j in {1..4};do
echo -e “\e[1;42m \e[0m\c”
echo -e “\e[1;43m \e[0m\c”
done
echo
else
for j in {1..4};do
echo -e “\e[1;43m \e[0m\c”
echo -e “\e[1;42m \e[0m\c”
done
echo
fi
done
done
例4:打印等腰三角形
#!/bin/bash
#
#********************************************************************
#Author: wqf
#QQ: 88888888
#Date: 2018-05-08
#FileName: sanjiaoixng.sh
#URL: http://www.magedu.com
#Description: The test script
#Copyright (C): 2018 All rights reserved
#********************************************************************
read -p “please input line num: ” line
declare -i linenum=0
for i in `seq 1 $line`;do
let ++linenum
star=$[linenum*2-1]
space=$[line-linenum]
for k in `seq $space`;do
echo -e ” \c”
done
for j in `seq $star`;do
echo -e “*\c”
done
echo
done
[root@centos6 data]#sanjiaoxing.sh
please input line num: 6
*
***
*****
*******
*********
***********
五、while循环
while CONDITION; do
循环体
done
CONDITION:循环控制条件;进入循环之前,先做一次判断;每一次循环之后会再次做判断;条件为“true”,则执行一次循环;直到条件测试状态为“false”终止循环
因此:CONDTION一般应该有循环控制变量;而此变量的值会在循环体不断地被修正
进入条件:CONDITION为true
退出条件:CONDITION为false
例1:求100以内奇数和
#!/bin/bash
#
declare -i sum=0
declare -i i=1
while [ $i -le 100 ];do
if [ $[i%2] -eq 1 ];then
sum+=i
fi
let i++
done
echo sum=$sum
例2:每7分钟执行某个命令
[root@centos6 data]#vim ping.sh
#!/bin/bash
#
while true;do
echo task
sleep 420
done
如果要防止脚本意外终端,可以用执行nohup scripts
例3:监控http服务,每10秒检查一次服务是否重启,如果没在线,就重启
#!/bin/bash
#
SLEEP=10
while true;do
if killall -0 httpd &>/dev/null;then
:
else
systemctl restart httpd
echo “at `date “+%F %T”` restart the httpd” >>/data/httpd.log
sleep $SLEEP
fi
done
killall -0 httpd 判断httpd服务是否在运行
六、until循环
until CONDITION; do
循环体
done
进入条件: CONDITION 为false
退出条件: CONDITION 为true
例1:如果wang用户登陆,则退出
#!/bin/bash
#
until w |grep wang &>/dev/null;do
sleep 1
done
echo “find wang login”
七、循环控制语句continue
用于循环体中
continue [N]:提前结束第N层的本轮循环,而直接进入下一轮判断;最内层为第1层
while CONDTIITON1; do
CMD1
…
if CONDITION2; then
continue
fi
CMDn
…
done
例1:continue
#!/bin/bash
#
for i in {1..10};do
if [ $i -eq 5 ];then
continue
fi
echo $i
done
执行结果是:当$i=5时,
[root@centos6 data]#continue.sh
1
2
3
4
6
7
8
9
10
例2:continue2
#!/bin/bash
#
for i in {1..3};do
for j in {1..10};do
if [ $j -eq 5 ];then
continue 2
fi
echo $j
done
echo
done
执行结果为:
[root@centos6 data]#continue.sh
1
2
3
4
1
2
3
4
1
2
3
4
continue2 退出的是外层的for循环语句,外层循环的echo执行也被终端
八、循环控制语句break
用于循环体中
break [N]:提前结束第N层循环,最内层为第1层
while CONDTIITON1; do
CMD1
…
if CONDITION2; then
break
fi
CMDn
…
done
例1:break
#!/bin/bash
#
for i in {1..3};do
for j in {1..10};do
if [ $j -eq 5 ];then
break
fi
echo $j
done
echo
done
执行结果为:
[root@centos6 data]#break.sh
1
2
3
4
1
2
3
4
1
2
3
4
此时break中断的是内部循环
例2:break2
#!/bin/bash
#
for i in {1..3};do
for j in {1..10};do
if [ $j -eq 5 ];then
break 2
fi
echo $j
done
echo
done
执行结果为:
[root@centos6 data]#break.sh
1
2
3
4
此时break 2中断的是外部循环
例3:猜数字,生成一个随机数,提示输入1到10以内的数字,然后比较大小,
#!/bin/bash
#
rand=$[RANDOM%11]
while read -p “please input a digit in 0 to 10: ” n;do
if [[ ! “$n” =~ ^[0-9]+$ ]];then
echo “please in put a digit 1-10”
continue
fi
if [ “$n” -lt “$rand” ];then
echo “less”
elif [ “$n” -gt “$rand” ];then
echo “more”
else
echo “right”
break 2
fi
done
九、循环控制shift命令
shift [n]
用于将参量列表 list 左移指定次数,缺省为左移一次。
参量列表 list 一旦被移动,最左端的那个参数就从列表中删除。while 循环遍历位置参量列表时,常用到 shift
./doit.sh a b c d e f g h
./shfit.sh a b c d e f g h
例1:创建用户,
#!/bin/bash
#
until [ -z “$1” ];do
useradd $1
echo “$1 has created”
shift 1
done
echo done
例2:打印所有的
#!/bin/bash
while [ $# -gt 0 ] # or (( $# > 0 ))
do
echo $*
shift
done
十、while特殊用法
while循环的特殊用法(遍历文件的每一行):
while read line; do
循环体
done < /PATH/FROM/SOMEFILE
依次读取/PATH/FROM/SOMEFILE文件中的每一行,且将行赋值给变量line
练
例1:文件/etc/passwd中uid为偶数的行,显示其用户名和id号
while read line;do
id=`echo $line|cut -d: -f3 `
user=`echo $line|cut -d: -f1`
if [ $[id%2] -eq 0 ];then
echo “$user:$id”
fi
done </etc/passwd
例2:检查分区利用率,利用率大于5报警,且显示其设备名
#!/bin/bash
df | while read line;do
if echo $line | grep “^/dev/sd” &>/dev/null;then
used=`echo $line | sed -nr “s/.*[ ]+([0-9]{1,3})%.*/\1/p”`
device=`echo $line | cut -d” ” -f1`
if [ $used -gt 5 ];then
echo “$device will full,used $used%”
fi
fi
done
十一、for循环的特殊格式:
for ((控制变量初始化;条件判断表达式;控制变量的修正表达式))
do
循环体
done
例1:1到100的和
#!/bin/bash
#
for ((sum=0,i=1;i<=100;i++ ));do
sum=$[sum+i]
done
echo sum=$sum
十二、select循环与菜单
select variable in list
do
循环体命令
done
select 循环主要用于创建菜单,按数字顺序排列的菜单项将显示在标准错误上,并显示 PS3 提示符,等待用户输入
用户输入菜单列表中的某个数字,执行相应的命令
用户输入被保存在内置变量 REPLY 中
select与case
select 是个无限循环,因此要记住用 break 命令退出循环,或用 exit 命令终止脚本。也可以按 ctrl+c 退出循环
select 经常和 case 联合使用
与 for 循环类似,可以省略 in list,此时使用位置参量
例1:
PS3=”please select scripts (1-4):”
select menu in etcbakup yum.sh alias.sh reset.sh;do
case $menu in
etcbakup)
echo “$REPLY:start bakup”
break
;;
yum.sh)
echo “$REPLY:start configuure yum”
break
;;
alias.sh)
echo “$REPLY:start configure alias”
break
;;
reset.sh)
echo “$REPLY:start reset the system environment”
break
;;
*)
echo “$REPLY:nothing to do”
;;
esac
done
十三、信号捕捉trap
trap ‘触发指令’ 信号
自定义进程收到系统发出的指定信号后,将执行触发指令,而不会执行原操作
trap ” 信号
忽略信号的操作
trap ‘-‘ 信号
恢复原信号的操作
trap -p
列出自定义信号操作
例1:捕捉信号2
trap “press the ctrl+c” 2 ###使2信号失效,且提示press the ctrl+c
for (( i=0;i<=10;i++ ));do
echo $i
sleep 1
done
trap “” 2 ###使2信号失效,不提示
for (( i=11;i<=20;i++ ));do
echo $i
sleep 1
done
trap “-” 2
for (( i=21;i<=30;i++ ));do
echo $i
sleep 1
done
十四、定义函数
函数由两部分组成:函数名和函数体
help function
语法一:
f_name (){
…函数体…
}
语法二:
function f_name {
…函数体…
}
语法三:
function f_name () {
…函数体…
}
十五、查看函数、删除函数
declare -f 查看系统所有函数
declare -f function_name 查看函数
unset function_name 删除函数
十六、函数中变量生效范围
默认函数和当前shell的变量使通用的
[root@centos6 ~]#func1 () { name=wang;echo “func1:$name”; }
[root@centos6 ~]#func1
func1:wang
[root@centos6 ~]#echo $name
wang
让函数中变量只在函数中生效加上local,如:func1 () { local name=wang;echo “func1:$name”; }
declare -i 在函数中声明变量相当赋予了local的特性,只在函数中生效
[root@centos6 ~]#func2 () { declare -i num=100;echo “$num”; }
[root@centos6 ~]#func2
100
[root@centos6 ~]#echo $num
declare -ig 在函数中声明变量的相当于普通变量,在函数和当前shell生效(在centos6上不支持,支持centos7)
[root@centos7 boot]#func1 () { declare -ig num=100;echo $num; }
[root@centos7 boot]#func1
100
[root@centos7 boot]#echo $num
100
十七、函数调用
例1:根据参数选择
#!/bin/bash
green_yellow (){
if [ “$1” = “-r” ];then
echo -e “\e[1;43m \e[1;42m \e[0m\c”
else
echo -e “\e[1;42m \e[1;43m \e[0m\c”
fi
echo
}
green_yellow
green_yellow -r
例2:写一个函数,显示当前系统版本,如果是6则显示oldversion,否则显示最新版本
方法一
[root@centos7 boot]#version () {
> ver=`sed -r “s/.*[ ]+([0-9]+)\..*/\1/” /etc/centos-release`
> if [ $ver -eq 6 ];then
> echo “oldversion”
> else
> echo “newversion”
> fi
> echo $ver
> }
方法二
[root@centos7 boot]#version() { ver=`sed -r “s/.*[ ]+([0-9]+)\..*/\1/” /etc/centos-release`;echo “$ver”; }
[root@centos7 boot]#version
7
[root@centos7 boot]#if [ `version` -eq 6 ];then echo version is old;else echo version is new;fi
version is new
方法三:根据return返回值判断
[root@centos7 boot]#version() { ver=`sed -r “s/.*[ ]+([0-9]+)\..*/\1/” /etc/centos-release`;return $ver; }
[root@centos7 boot]#version
[root@centos7 boot]#echo $?
7
[root@centos7 boot]#if [ `version` -eq 6 ];then echo version is old;else echo version is new;fi
version is new
十八、实现多个脚本调用一个函数
编辑一个文件,如functions,把写好的函数都写入文件。然后在别的脚本中调用
写入脚本格式简单如下:
#!/bin/bash
source /data/functions
函数1
函数2
………..
十九、action函数
[root@centos7 boot]#source /etc/init.d/functions
[root@centos7 boot]#action “command successd”
command successd [ OK ]
[root@centos7 boot]#action “command failed” /bin/false
command failed [FAILED]
二十、定义全局函数
全局函数在子shell生效,在脚本调用脚本时可用
[root@centos7 boot]#func1 () { local num=100;echo $num; }
[root@centos7 boot]#func1
100
[root@centos7 boot]#export -f func1
二十一、数组
变量:存储单个元素的内存空间
数组:存储多个元素的连续的内存空间,相当于多个变量的集合
数组名和索引
索引:编号从0开始,属于数值索引
注意:索引可支持使用自定义的格式,而不仅是数值格式,即为关联索引,bash4.0版本之后开始支持
bash的数组支持稀疏格式(索引不连续)
声明数组:
declare -a ARRAY_NAME 普通数组
declare -A ARRAY_NAME: 关联数组 必须先声明,后使用
注意:两者不可相互转换
二十二、数组元素的赋值:
(1) 一次只赋值一个元素
ARRAY_NAME[INDEX]=VALUE
weekdays[0]=”Sunday”
weekdays[4]=”Thursday”
(2) 一次赋值全部元素
ARRAY_NAME=(“VAL1” “VAL2” “VAL3″ …)
(3) 只赋值特定元素
ARRAY_NAME=([0]=”VAL1″ [3]=”VAL2” …)
(4) 交互式数组值对赋值
read -a ARRAY
1.一次只赋值一个元素
[root@centos6 data]#declare -a name[1]=a
[root@centos6 data]#declare -a name[2]=b
[root@centos6 data]#declare -a name[3]=c
显示所有数组元素
[root@centos6 data]#echo ${name[*]}
a b c
2.一次赋值多个元素(可以生成列表)
例1:
[root@centos6 data]#declare -a name=(“c” “d” “e”)
[root@centos6 data]#echo ${name[*]}
c d e
例2:生成列表
[root@centos6 data]#number=({1..10})
[root@centos6 data]#echo ${number[*]}
1 2 3 4 5 6 7 8 9 10
例3:
[root@centos6 data]#filename=(/data/*.sh)
[root@centos6 data]#echo ${filename[@]}
/data/3.sh /data/67_createuser.sh /data/9×9.sh /data/a.sh /data/checkint.sh
3.赋值特定的元素
[root@centos6 data]#name=([1]=x [2]=y)
[root@centos6 data]#echo ${name[*]}
x y
4.交互式数组赋值
例1:
[root@centos6 data]#read -a name
wang li zhang zhao
[root@centos6 data]#echo ${name[*]}
wang li zhang zhao
显示所有数组:
declare -a
引用数组
引用数组元素:
${ARRAY_NAME[INDEX]}
注意:省略[INDEX]表示引用下标为0的元素
引用数组所有元素:
${ARRAY_NAME[*]}
${ARRAY_NAME[@]}
数组的长度(数组中元素的个数):
${#ARRAY_NAME[*]}
${#ARRAY_NAME[@]}
删除数组中的某元素:导致稀疏格式
unset ARRAY[INDEX]
删除整个数组:
unset ARRAY
二十三、在已有的数组后面添加新元素
首先不知道哪些下标被占用,可以这样定义declare -a name[${#name[*]}]=wang
${#name[*]}代表元素的个数
二十四、生成20个随机数保存于数组中,并找出其最大值和最小值
#!/bin/bash
#
declare -a rand
for ((i=0;i<20;i++));do
rand[$i]=$RANDOM
if [ $i -eq 0 ];then
max=${rand[$i]}
min=${rand[$i]}
else
[ $max -lt ${rand[$i]} ] && max=${rand[$i]}
[ $min -gt ${rand[$i]} ] && min=${rand[$i]}
fi
done
echo ${rand[*]}
echo $max $min
二十五、数组赋值
#!/bin/bash
#
declare -A disk
df |grep ^/dev/sd |while read line;do
device=`echo $line|cut -d” ” -f1`
used=`echo $line |sed -r “s/.*[ ]([0-9]{1,3}).*/\1/”`
disk[$device]=$used
echo ${disk[$device]}
done
二十六、字符串切片
${#var}:返回字符串变量var的长度
例1:
[root@centos6 ~]#str=`echo {a..z}|tr -d ” “`
[root@centos6 ~]#echo $str
abcdefghijklmnopqrstuvwxyz
[root@centos6 ~]#echo ${#str}
26
${var:offset}:表示跳过几个开始取值
例:跳过5个开始取值
[root@centos6 ~]#echo $str
abcdefghijklmnopqrstuvwxyz
[root@centos6 ~]#echo ${str:5}
fghijklmnopqrstuvwxyz
${var:offset:N }:表示跳过前几个子浮窗,然后取N个子浮窗
例:
[root@centos6 ~]#echo $str
abcdefghijklmnopqrstuvwxyz
[root@centos6 ~]#echo ${str:3:4}
defg
${var: -offset}:表示取后面倒数几个字符,注意-offset前面要加空格
例:
[root@centos6 ~]#echo $str
abcdefghijklmnopqrstuvwxyz
[root@centos6 ~]#echo ${str: -3}
xyz
${var:offset:-length}:从最左侧跳过offset字符,一直向右取到距离最右侧lengh个字符之前的内容(去头去尾取中间)
例:
[root@centos7 ~]#echo $str
abcdefghijklmnopqrstuvwxyz
[root@centos7 ~]#echo ${str:3:-3}
defghijklmnopqrstuvw
例2:取后面4个,再去掉最后两个
[root@centos7 ~]#echo $str
abcdefghijklmnopqrstuvwxyz
[root@centos7 ~]#echo ${str: -4:-2}
wx
命令matemp
创建随机文件
[root@centos6 data]#mktemp /data/tmpXXXX
/data/tmp4YEW
创建随机目录-d
[root@centos6 data]#mktemp -d /data/tmpXXXXX
/data/tmpq9VGE
-p指定生成文件后放置的目录
[root@centos6 data]#mktemp -p /data/ tmpXXXXXXX
/data/tmpLCNalET
-p指定目录可以用变量替代,执行的结果也可以放置到一个变量之中,方便以后查找删除
tmpfile=`mktemp -p “$dir” tmpXXXX
rm -rf $tempfile
install命令:
install [OPTION]… [-T] SOURCE DEST 单文件
install [OPTION]… SOURCE… DIRECTORY
install [OPTION]… -t DIRECTORY SOURCE…
install [OPTION]… -d DIRECTORY…创建空目录
选项:
-m MODE,默认755
-o OWNER
-g GROUP
示例:
install -m 700 -o wang -g admins srcfile desfile
install –m 770 –d /testdir/installdir
本文来自投稿,不代表Linux运维部落立场,如若转载,请注明出处:http://www.178linux.com/98464