承接第一部分进行总结分析
read
-p"prompt" //提示
-ttimeout
给变量默认值
varName=${varName:-value}
如果varName不空,则返回varName的值;否则varName会使用value作为其值
使用read参数[-p]后,允许在[-p]后面跟一字符串,在字符串后面跟n个shell变量。n个shell变量用来接收从shell界面输入的字符串
[-p]用法:read –p “string” var1 var2…varn
练习:通过键盘给定一个文件的路径,来判定文件内容类型
#!/bin/bash
read –p “Enter a file name:” fileName
type $fileName
通过键盘给定一个路径,默认为/,来判定目录下文件内容类型
例如:输入用户名,可返回其shell
#!/bin/bash
#
read-p "Plz input a username: " userName
ifid $userName &> /dev/null; then
echo "The shell of $userName is `grep"^$userName\>" /etc/passwd | cut -d: -f7`."
else
echo "No such user. stupid."
Fi
例子:显示一个如下菜单给用户:
cpu)show cpu infomation
mem)show memory infomation
*)quit
1、如果用户选择了cpu,则显示/proc/cpuinfo文件的内容;
2、如果用户选择了mem,则显示/proc/meminfo文件的内容;
3、退出
#!/bin/bash
#
echo"---------menu----------"
echo"cpu) show cpu infomation"
echo"mem) show memory infomation"
echo"*) quit"
echo"-------menu------------"
read-p "Plz give your choice: " choice
if[ "$choice" == ‘cpu‘ ]; then
cat /proc/cpuinfo
elif[ "$choice" == ‘mem‘ ]; then
cat /proc/meminfo
else
echo "Quit"
exit 3
fi
在第二个EOF前不要有换行、制表符或者空格
#!/bin/bash
#
cat<< EOF
-------menu------------
cpu)show cpu infomation
mem)show memory infomation
*)quit
-------menu------------
EOF
read-p "Plz give your choice: " choice
if[ "$choice" == ‘cpu‘ ]; then
cat /proc/cpuinfo
elif[ "$choice" == ‘mem‘ ]; then
cat /proc/meminfo
else
echo "Quit"
exit 3
fi
语法:
function F_NAME {
函数体
}
F_NAME() {
函数体
}
可调用:使用函数名
函数名出现的地方,会被自动替换为函数;
脚本:
函数的返回值:
函数的执行结果返回值:代码的输出
函数中的打印语句:echo, print
函数中调用的系统命令执行后返回的结果
执行状态返回值:
函数体中最后一次执行的命令状态结果
自定函数执行状态的返回值:return #
函数可以接受参数:
在函数体中调用函数参数的方式同脚本中调用脚本参数的方式:位置参数
$1, $2, ...
$#, $*, $@
示例:服务脚本示例
#!/bin/bash
#
# chkconfig: 2345 67 34
#
srvName=$(basename $0)
lockFile=/var/lock/subsys/$srvName
start() {
if [ -f $lockFile];then
echo "$srvName is already running."
return 1
else
touch $lockFile
[ $? -eq 0 ] && echo "Starting $srvNameOK."
return 0
fi
}
stop() {
if [ -f $lockFile];then
rm -f $lockFile &> /dev/null
[ $? -eq 0 ] && echo "Stop $srvName OK"&& return 0
else
echo "$srvName is not started."
return 1
fi
}
status() {
if [ -f $lockFile ];then
echo "$srvName is running."
else
echo "$srvName is stopped."
fi
return 0
}
usage() {
echo "Usage:$srvName {start|stop|restart|status}"
return 0
}
case $1 in
start)
start
;;
stop)
stop ;;
restart)
stop
start ;;
status)
status ;;
*)
usage
exit 1 ;;
esac
练习:写一个脚本,完成如下功能(使用函数):
1、提示用户输入一个可执行命令;
2、获取这个命令所依赖的所有库文件(使用ldd命令);
3、复制命令至/mnt/sysroot/对应的目录中
解释:假设,如果复制的是cat命令,其可执行程序的路径是/bin/cat,那么就要将/bin/cat复制到/mnt/sysroot/bin/目录中,如果复制的是useradd命令,而useradd的可执行文件路径为/usr/sbin/useradd,那么就要将其复制到/mnt/sysroot/usr/sbin/目录中;
4、复制各库文件至/mnt/sysroot/对应的目录中;
#!/bin/bash
#
target=/mnt/sysroot/
[ -d $target ] || mkdir $target
preCommand() {
if which $1 &> /dev/null; then
commandPath=`which--skip-alias $1`
return0
else
echo"No such command."
return1
fi
}
commandCopy() {
commandDir=`dirname $1`
[ -d ${target}${commandDir} ] || mkdir-p ${target}${commandDir}
[ -f ${target}${commandPath} ] || cp $1${target}${commandDir}
}
libCopy() {
for lib in `ldd $1 | egrep -o"/[^[:space:]]+"`; do
libDir=`dirname$lib`
[ -d${target}${libDir} ] || mkdir -p ${target}${libDir}
[ -f${target}${lib} ] || cp $lib ${target}${libDir}
done
}
read -p "Plz enter a command: "command
until [ "$command" == ‘quit‘ ];do
if preCommand $command &>/dev/null; then
commandCopy $commandPath
libCopy $commandPath
fi
read -p "Plz enter a command: "command
done
信号种类
1) SIGHUP本信号在用户终端连接(正常或非正常)结束时发出,通常是在终端的控制进程结束时,通知同一session内的各个作业,这时它们与控制端不再关联。
2) SIGINT程序终止(interrupt)信号,在用户键入INTR字符(通常是Ctrl-C)发出
3) SIGQUIT和SIGINT类似,但由QUIT字符(通常是Ctrl-/)来控制。进程在因收到SIGQUIT退出时会产生core文件,在这个意义1类似于一个程序错误信号。
4) SIGILL执行了非法指令,通常是因为可执行文件本身出现错误,或者试图执行数据段。堆栈溢出时也有可能产生这个信号
trap命令用于在shell程序中捕捉到信号,之后可以有三种反应方式:
(1)执行一段程序来处理这一信号
(2)接受信号的默认操作
(3)忽视这一信号
trap对上面三种方式提供了三种基本形式:
第一种形式的trap命令在shell接收到signallist清单中数值相同的信号时,将执行双引号中的命令串。
trap ‘commands‘ signal-list
trap "commands" signal-list
第二种形式的trap命令恢复信号的默认操作:trap signal-list
第三种形式的trap命令允许忽视信号:trap " " signal-list
trap ‘COMMAND‘ SIGINT(表示关闭进程)
例:写一个脚本,能够ping探测指定网络内的所有主机是否在线,当没有执行完时可接收ctrl+c命令退出。
#!/bin/bash
quitScript() {
echo "Quit..."
}
trap ‘quitScript; exit 5‘ SIGINT
cnetPing() {
for i in {1..254}; do
if ping -c 1 -W 1 $1.$i &>/dev/null; then
echo "$1.$i is up."
else
echo "$1.$i is down."
fi
done
}
bnetPing() {
for j in {0..255}; do
cnetPing $1.$j
done
}
anetPing() {
for m in {0..255}; do
bnetPing $1.$m
done
}
netType=`echo $1 | cut -d"." -f1`
if [ $netType -ge 1 -a $netType -le 126 ];then
anetPing $netType
elif [ $netType -ge 128 -a $netType -le 191]; then
bnetPing $(echo $1 | cut -d‘.‘ -f1,2)
elif [ $netType -ge 192 -a $netType -le 223]; then
cnetPing $(echo $1 | cut -d‘.‘ -f1-3)
else
echo "Wrong"
exit 2
fi
数组:连续的多个独立内存空间,每个内存空间相当于一个变量
数组元素:数组名+索引(从0开始编号)
索引的表示方式:
数字索引:a[index]
a[0], a[1]
bash 4.0的关联数组
a[hello], a[hi]
声明数组:declare -a ARRAR_NAME
关联数组:declare -A ARRAY_NAME
支持稀疏格式:仅一维数组
数组的赋值:
(1)一次对一个元素赋值:
a[0]=$RANDOM
...
echo ${a[0]}
(2)一次对全部元素赋值:
a=(red blue yellowgreen)
一对括号表示是数组,数组元素用“空格”符号分隔开。
(3)按索引进行赋值:
a=([0]=green [3]=red[2]=blue [6]=yellow)
(4)命令替换:
logs=($(ls /var/log/*.log))
或者logs=(/var/log/*.log)
echo ${logs[0]}
(5)用户输入
read -a ARRAY
数组的访问:
用索引访问:ARRAY[index]
数组的长度:
${#ARRAY[*]}
${#ARRAY[@]}
eg:echo ${#test[*]}
echo ${#test[@]}
练习:写一个脚本,生成10个随机数,保存至数组中;而后显示数组下标为偶数的元素;
#!/bin/bash
for i in {0..9};do
num[$i]=$RANDOM
if [ $[$i%2] -eq 0];then
echo "a[i] is${a[i]}"
fi
done
从数组中挑选某元素:
${ARRAY[@]:offset:number}
切片:
offset: 偏移的元素个数
number: 取出的元素的个数
${ARRAY[@]:offset}:取出偏移量后的所有元素
${ARRAY[@]}: 取出所有元素
数组复制:
要使用${ARRAY[@]}
$@: 每个参数是一个独立的串
$*: 所有参数是一个串
向数组追加元素:非稀疏格式
mylogs,
mylogs[${#week[@]}]
示例:复制一个数组中下标为偶数的元素至一个新数组中
#!/bin/bash
declare -a mylogs
logs=(/var/log/*.log)
echo ${logs[@]}
for i in `seq 0 ${#logs[@]}`; do
if [ $[$i%2] -eq 0];then
index=${#mylogs[@]}
mylogs[$index]=${logs[$i]}
fi
done
echo ${mylogs[@]}
从数组中删除元素:unset ARRAY[index]
练习1:生成10个随机数,升序排序
#!/bin/bash
for((i=0;i<10;i++))
do
rnd[$i]=$RANDOM
done
echo -e "total=${#rnd[@]}\n${rnd[@]}\nBegin to sort"
for((i=9;i>=1;i--))
do
for((j=0;j<i;j++))
do
if [ ${rnd[$j]} -gt${rnd[$[$j+1]]} ] ;then
swapValue=${rnd[$j]}
rnd[$j]=${rnd[$[$j+1]]}
rnd[$[$j+1]]=$swapValue
fi
done
done
echo ${rnd[@]}
练习2:打印九九乘法表
#!/bin/bash
for((i=1;i<=9;i++))
do
strLine=""
for((j=1;i<=9;j++))
do
strLine=$strLine"$i*$j="$[$i*$j]"\t"
[ $i -eq $j ] && echo -e $strLine && break
done
done
字符串切片:
${string:offset:length}
取尾部的指定个数的字符:
${string: -length}
取子串:基于模式
${variable#*word}:在variable中存储字串上,自左而右,查找第一次出现word,删除字符开始至此word处的所有内容;
${variable##*word}:在variable中存储字串上,自左而右,查找最后一次出现word,删除字符开始至此word处的所有内容;
file=‘/var/log/messages‘
${file#*/}: 返回的结果是var/log/messages
${file##*/}: 返回messages
${variable%word*}: 在variable中存储字串上,自右而左,查找第一次出现word,删除此word处至字串尾部的所有内容;
${variable%%world*}:在variable中存储字串上,自右而左,查找最后一次出现word,删除此word处至字串尾部的所有内容;
file=‘/var/log/messages‘
${file%*/}: 返回的结果是/var/log
${file%%*/}: 返回结果为空
phonenumber=‘010-110-8‘
${phonenumber%%-*}
${phonenumber##*-}
url="http://www.magedu.com:80"
取端口:${url##*:}
取协议:${url%%:*}
查找替换:
${variable/pattern/substi}: 替换第一次出现
${variable//pattern/substi}:替换所有的出现
${variable/#pattern/substi}:替换行首被pattern匹配到的内容
${variable/%pattern/substi}: 行尾
pattern可以使用globbing中的元字符:
*
?
查找删除:
${variable/pattern}
${variable//pattern}
${variable/#pattern}
${variable/%pattern}
大小写转换:
小-->大:${variable^^}
大-->小:${variable,,}
只能对变量的单个字符做操作,eg:echo ${user^^a}
变量赋值操作:
${parameter:-word}
Use Default Values. If parameter is unset ornull, the expansion of word is substituted. Otherwise, the value of parameter is
substituted.
${parameter:=word}
Assign Default Values. If parameter is unset or null, the expansionof word is assigned to parameter. Thevalue of parameter is
then substituted. Positional parameters and special parametersmay not be assigned to in this way.
${parameter:?word}
Display Error if Null or Unset. If parameter is null or unset, the expansionof word (or a message to that effect if word is not
present) is written to the standarderror and the shell, if it is not interactive, exits. Otherwise, the value of parameter is
substituted.
${parameter:+word}
Use Alternate Value. If parameter is null or unset, nothing issubstituted, otherwise the expansion of word is substituted.
${variable:-string}
variable为空或未设定,那么返回string,否则,返回variable变量的值;
${variable:=string}
variable为空或未设定,则返回string,且将string赋值给变量variable,否则,返回variable的值;
为脚本使用配置文件,并确保某变量有可用值的方式
variable=${variable:-defaultvaule}
eg:
[ -f etc/sysconfig/test ] &&source /etc/sysconfig/test
myvar=${myvar:-www.mageedu.com}
echo $myvar
练习:读取/etc/sysconfig/network文件,利用其HOSTNAME变量的值设置主机名;
9.4 bash编程之补充
mktemp命令:
mktemp [OPTIONS] filename.XXX
-d: 创建临时目录
--tmpdir=/path/to/somewhere :指定临时文件所在的目录
mktemp /tmp/tmp.XXX #XXX生成相同数量随机字符
mktemp --tmpdir=/var/tmp tmp.XXX #指定目录创建临时文件
mktemp --tmpdir=/var/tmp -d tmp.XXX #指定目录创建临时目录
install命令:
install [OPTIONS] SOURCE DEST
install [OPTIONS] SOURCE... DIR
install [OPTIONS] -d DIR ...
增强型的复制命令:
-o OWNER
-g GROUP
-m MODE
-d : 创建目录
install /etc/fstab /tmp #复制文件到指定目录
install --mode=644 /etc/fstab /tmp/ #复制时指定权限
install --owner=scholar /etc/fstab /tmp #复制时指定属主
install --group=scholar /etc/fstab /tmp #复制时指定属组
install -d /tmp/install #创建目录
原文地址:http://heroleilei0627.blog.51cto.com/4835750/1651086