标签:变量赋值 cas 实现 mod 开始 cond 本地变量 dex 空间
bash脚本编程之用户交互:
read [option]… [name …]
-p ‘PROMPT’
-t TIMEOUT
bash -n /path/to/some_script
检测脚本中的语法错误
bash -x /path/to/some_script
调试执行
示例:
#!/bin/bash # Version: 0.0.1 # Author: mrlapulga # Description: read testing read -p "Enter a disk special file: " diskfile [ -z "$diskfile" ] && echo "Fool" && exit 1 if fdisk -l | grep "^Disk $diskfile" &> /dev/null; then fdisk -l $diskfile else echo "Wrong disk special file." exit 2 fi
#!/bin/bash # read -p "Enter a file path: " filename if [ -z "$filename" ]; then echo "Usage: Enter a file path." exit 2 fi if [ ! -e $filename ]; then echo "No such file." exit 3 fi if [ -f $filename ]; then echo "A common file." elif [ -d $filename ]; then echo "A directory." elif [ -L $filename ]; then echo "A symbolic file." else echo "Other type." fi
注意:if语句可嵌套;
循环:for
循环体:要执行的代码;可能要执行n遍;
进入条件:
退出条件:
for循环:
for 变量名 in 列表; do
循环体
done
执行机制:
依次将列表中的元素赋值给“变量名”; 每次赋值后即执行一次循环体; 直到列表中的元素耗尽,循环结束;
示例:添加10个用户, user1-user10;密码同用户名;
#!/bin/bash
#
if [ ! $UID -eq 0 ]; then
echo "Only root."
exit 1
fi
for i in {1..10}; do
if id user$i &> /dev/null; then
echo "user$i exists."
else
useradd user$i
if [ $? -eq 0 ]; then
echo "user$i" | passwd --stdin user$i &> /dev/null
echo "Add user$i finished."
fi
fi
done
列表生成方式:
(1) 直接给出列表;
(2) 整数列表:
(a) {start..end}
(b) $(seq [start [step]] end)
(3) 返回列表的命令;
$(COMMAND)
(4) glob
(b) 变量引用;
$@, $*
示例:判断某路径下所有文件的类型
#!/bin/bash # for file in $(ls /var); do if [ -f /var/$file ]; then echo "Common file." elif [ -L /var/$file ]; then echo "Symbolic file." elif [ -d /var/$file ]; then echo "Directory." else echo "Other type." fi done
示例:
#!/bin/bash
#
declare -i estab=0
declare -i listen=0
declare -i other=0
for state in $( netstat -tan | grep "^tcp\>" | awk ‘{print $NF}‘); do
if [ "$state" == ‘ESTABLISHED‘ ]; then
let estab++
elif [ "$state" == ‘LISTEN‘ ]; then
let listen++
else
let other++
fi
done
echo "ESTABLISHED: $estab"
echo "LISTEN: $listen"
echo "Unkown: $other"
#!/bin/bash
#
net=‘172.16.250‘
uphosts=0
downhosts=0
for i in {1..20}; do
ping -c 1 -w 1 ${net}.${i} &> /dev/null
if [ $? -eq 0 ]; then
echo "${net}.${i} is up."
let uphosts++
else
echo "${net}.${i} is down."
let downhosts++
fi
done
echo "Up hosts: $uphosts."
echo "Down hosts: $downhosts."
while循环:
while CONDITION; do
循环体
done
CONDITION:循环控制条件;进入循环之前,先做一次判断;每一次循环之后会再次做判断;
条件为“true”,则执行一次循环;直到条件测试状态为“false”终止循环;
因此:CONDTION一般应该有循环控制变量;而此变量的值会在循环体不断地被修正;
示例:求100以内所有正整数之和;
#!/bin/bash # declare -i sum=0 declare -i i=1 while [ $i -le 100 ]; do let sum+=$i let i++ done echo "$i" echo "Summary: $sum." 练习:添加10个用户 user1-user10 #!/bin/bash # declare -i i=1 declare -i users=0 while [ $i -le 10 ]; do if ! id user$i &> /dev/null; then useradd user$i echo "Add user: user$i." let users++ fi let i++ done echo "Add $users users."
#!/bin/bash # declare -i i=1 declare -i uphosts=0 declare -i downhosts=0 net=‘172.16.250‘ while [ $i -le 20 ]; do if ping -c 1 -w 1 $net.$i &> /dev/null; then echo "$net.$i is up." let uphosts++ else echo "$net.$i is down." let downhosts++ fi let i++ done echo "Up hosts: $uphosts." echo "Down hosts: $downhosts."
#!/bin/bash
#
for j in {1..9}; do
for i in $(seq 1 $j); do
echo -e -n "${i}X${j}=$[$i*$j]\t"
done
echo
done
#!/bin/bash
#
declare -i i=1
declare -i j=1
while [ $j -le 9 ]; do
while [ $i -le $j ]; do
echo -e -n "${i}X${j}=$[$i*$j]\t"
let i++
done
echo
let i=1
let j++
done
#!/bin/bash # declare -i max=0 declare -i min=0 declare -i i=1 while [ $i -le 9 ]; do rand=$RANDOM echo $rand if [ $i -eq 1 ]; then max=$rand min=$rand fi if [ $rand -gt $max ]; then max=$rand fi if [ $rand -lt $min ]; then min=$rand fi let i++ done echo "MAX: $max." echo "MIN: $min."
#!/bin/bash
#
declare -i j=1
declare -i i=1
until [ $j -gt 9 ]; do
until [ $i -gt $j ]; do
echo -n -e "${i}X${j}=$[$i*$j]\t"
let i++
done
echo
let i=1
let j++
done
循环控制语句(用于循环体中):
continue [N]:提前结束第N层的本轮循环,而直接进入下一轮判断;
while CONDTIITON1; do
CMD1
…
if CONDITION2; then
continue
fi
CMDn
…
done
break [N]:提前结束循环;
while CONDTIITON1; do
CMD1
…
if CONDITION2; then
break
fi
CMDn
…
done
示例1:求100以内所有偶数之和;要求循环遍历100以内的所正整数;
#!/bin/bash # declare -i i=0 declare -i sum=0 until [ $i -gt 100 ]; do let i++ if [ $[$i%2] -eq 1 ]; then continue fi let sum+=$i done echo "Even sum: $sum"
创建死循环:
while true; do
循环体
done
until false; do
循环体
done
示例2:每隔3秒钟到系统上获取已经登录的用户的信息;如果docker登录了,则记录于日志中,并退出;
#!/bin/bash # read -p "Enter a user name: " username while true; do if who | grep "^$username" &> /dev/null; then break fi sleep 3 done echo "$username logged on." >> /tmp/user.log 第二种实现: #!/bin/bash # read -p "Enter a user name: " username until who | grep "^$username" &> /dev/null; do sleep 3 done echo "$username logged on." >> /tmp/user.log
while循环的特殊用法(遍历文件的每一行):
while read line; do
循环体
done < /PATH/FROM/SOMEFILE
依次读取/PATH/FROM/SOMEFILE文件中的每一行,且将行赋值给变量line:
示例:找出其ID号为偶数的所有用户,显示其用户名及ID号;
#!/bin/bash # while read line;do if [ $[`echo $line | cut -d: -f3` % 2] -eq 0 ];then echo -e -n "username: `echo $line | cut -d: -f1`\t" echo "uid: `echo $line | cut -d: -f3 `" fi done < /etc/passwd
for循环的特殊格式:
for ((控制变量初始化;条件判断表达式;控制变量的修正表达式)); do
循环体
done
控制变量初始化:仅在运行到循环代码段时执行一次;
控制变量的修正表达式:每轮循环结束会先进行控制变量修正运算,而后再做条件判断;
示例1:求100以内所正整数之和;
#!/bin/bash # declare -i sum=0 for ((i=1;i<=100;i++)); do let sum+=$i done echo "Sum: $sum."
#!/bin/bash
#
for((j=1;j<=9;j++));do
for((i=1;i<=j;i++))do
echo -e -n "${i}X${j}=$[$i*$j]\t"
done
echo
done
练习:写一个脚本,完成如下任务
(1) 显示一个如下菜单:
cpu) show cpu information;
mem) show memory information;
disk) show disk information;
quit) quit
(2) 提示用户选择选项;
(3) 显示用户选择的内容;
#!/bin/bash # cat << EOF cpu) show cpu information; mem) show memory information; disk) show disk information; quit) quit ============================ EOF read -p "Enter a option: " option while [ "$option" != ‘cpu‘ -a "$option" != ‘mem‘ -a "$option" != ‘disk‘ -a "$option" != ‘quit‘ ]; do read -p "Wrong option, Enter again: " option done if [ "$option" == ‘cpu‘ ]; then lscpu elif [ "$option" == ‘mem‘ ]; then cat /proc/meminfo elif [ "$option" == ‘disk‘ ]; then fdisk -l else echo "Quit" exit 0 fi
进一步地:
用户选择,并显示完成后不退出脚本;而是提示用户继续选择显示其它内容;直到使用quit方始退出;
条件判断:case语句
case 变量引用 in
PAT1)
分支1
;;
PAT2)
分支2
;;
…
*)
默认分支
;;
esac
case支持glob风格的通配符:
*: 任意长度任意字符;
?: 任意单个字符;
[]:指定范围内的任意单个字符;
a|b: a或b
示例:
#!/bin/bash # cat << EOF cpu) show cpu information; mem) show memory information; disk) show disk information; quit) quit ============================ EOF read -p "Enter a option: " option while [ "$option" != ‘cpu‘ -a "$option" != ‘mem‘ -a "$option" != ‘disk‘ -a "$option" != ‘quit‘ ]; do read -p "Wrong option, Enter again: " option done case "$option" in cpu) lscpu ;; mem) cat /proc/meminfo ;; disk) fdisk -l ;; *) echo "Quit..." exit 0 ;; esac
#!/bin/bash
#
function adduser {
if id $username &> /dev/null; then
echo "$username exists."
return 1
else
useradd $username
[ $? -eq 0 ] && echo "Add $username finished." && return 0
fi
}
for i in {1..10}; do
username=myuser$i
adduser
done
示例:服务脚本
#!/bin/bash
#
# chkconfig: - 88 12
# description: test service script
#
prog=$(basename $0)
lockfile=/var/lock/subsys/$prog
start() {
if [ -e $lockfile ]; then
echo "$prog is aleady running."
return 0
else
touch $lockfile
[ $? -eq 0 ] && echo "Starting $prog finished."
fi
}
stop() {
if [ -e $lockfile ]; then
rm -f $lockfile && echo "Stop $prog ok."
else
echo "$prog is stopped yet."
fi
}
status() {
if [ -e $lockfile ]; then
echo "$prog is running."
else
echo "$prog is stopped."
fi
}
usage() {
echo "Usage: $prog {start|stop|restart|status}"
}
if [ $# -lt 1 ]; then
usage
exit 1
fi
case $1 in
start)
start
;;
stop)
stop
;;
restart)
stop
start
;;
status)
status
;;
*)
usage
esac
函数返回值:
函数的执行结果返回值:
(1) 使用echo或print命令进行输出;
(2) 函数体中调用命令的执行结果;
函数的退出状态码:
(1) 默认取决于函数体中执行的最后一条命令的退出状态码;
(2) 自定义退出状态码:
return
函数可以接受参数:
传递参数给函数:调用函数时,在函数名后面以空白分隔给定参数列表即可;例如“testfunc arg1 arg2 …”
在函数体中当中,可使用$1, $2, …调用这些参数;还可以使用$@, $*, $#等特殊变量;
示例:添加10个用户
#!/bin/bash
#
function adduser {
if [ $# -lt 1 ]; then
return 2
# 2: no arguments
fi
if id $1 &> /dev/null; then
echo "$1 exists."
return 1
else
useradd $1
[ $? -eq 0 ] && echo "Add $1 finished." && return 0
fi
}
for i in {1..10}; do
adduser myuser$i
done
变量作用域:
本地变量:当前shell进程;为了执行脚本会启动专用的shell进程;因此,本地变量的作用范围是当前shell脚本程序文件;
局部变量:函数的生命周期;函数结束时变量被自动销毁;
如果函数中有局部变量,其名称同本地变量;
N!=N(n-1)(n-2)...1
n(n-1)! = n(n-1)(n-2)!
#!/bin/bash
#
fact() {
if [ $1 -eq 0 -o $1 -eq 1 ]; then
echo 1
else
echo $[$1*$(fact $[$1-1])]
fi
}
fact 5
练习:求n阶斐波那契数列;
#!/bin/bash
#
fab() {
if [ $1 -eq 1 ]; then
echo 1
elif [ $1 -eq 2 ]; then
echo 1
else
echo $[$(fab $[$1-1])+$(fab $[$1-2])]
fi
}
fab 7
#!/bin/bash
#
declare -a rand
declare -i max=0
for i in {0..9}; do
rand[$i]=$RANDOM
echo ${rand[$i]}
[ ${rand[$i]} -gt $max ] && max=${rand[$i]}
done
echo "Max: $max"
练习:写一个脚本
定义一个数组,数组中的元素是/var/log目录下所有以.log结尾的文件;要统计其下标为偶数的文件中的行数之和;
#!/bin/bash
#
declare -a files
files=(/var/log/*.log)
declare -i lines=0
for i in $(seq 0 $[${#files[*]}-1]); do
if [ $[$i%2] -eq 0 ];then
let lines+=$(wc -l ${files[$i]} | cut -d‘ ‘ -f1)
fi
done
echo "Lines: $lines."
引用数组中的元素:
所有元素:${ARRAY[@]}, ${ARRAY[*]}
数组切片:${ARRAY[@]:offset:number}
offset: 要跳过的元素个数
number: 要取出的元素个数,取偏移量之后的所有元素:${ARRAY[@]:offset};
向数组中追加元素:
ARRAY[${#ARRAY[*]}]
删除数组中的某元素:
unset ARRAY[INDEX]
关联数组:
declare -A ARRAY_NAME
ARRAY_NAME=([index_name1]=’val1′ [index_name2]=’val2′ …)
bash的字符串处理工具:
字符串切片:
${var:offset:number}
取字符串的最右侧几个字符:${var: -lengh}
注意:冒号后必须有一空白字符;
基于模式取子串:
${var#*word}:其中word可以是指定的任意字符;功能:自左而右,查找var变量所存储的字符串中,第一次出现的word, 删除字符串开头至第一次出现word字符之间的所有字符;
${var##*word}:同上,不过,删除的是字符串开头至最后一次由word指定的字符之间的所有内容;
file=”/var/log/messages”
${file##*/}: messages
${var%word*}:其中word可以是指定的任意字符;功能:自右而左,查找var变量所存储的字符串中,第一次出现的word, 删除字符串最后一个字符向左至第一次出现word字符之间的所有字符;
file=”/var/log/messages”
${file%/*}: /var/log
${var%%word*}:同上,只不过删除字符串最右侧的字符向左至最后一次出现word字符之间的所有字符;
示例:url=http://www.mrlapulga.com:80
${url##*:}
${url%%:*}
查找替换:
${var/pattern/substi}:查找var所表示的字符串中,第一次被pattern所匹配到的字符串,以substi替换之;
${var//pattern/substi}: 查找var所表示的字符串中,所有能被pattern所匹配到的字符串,以substi替换之;
标签:变量赋值 cas 实现 mod 开始 cond 本地变量 dex 空间
原文地址:http://www.cnblogs.com/mrlapulga/p/6821068.html