Shell编程基础 part 2/2
6 命令行参数
特殊变量$*, $1, $2, ...$9包含了用户从命令行输入的参数; 简单的命令行语法(强制性参数和查看帮助的-h选项); 在编写复杂程序时, 可能需要更多的自定义选项; 通常的惯例是在所有可选的参数之前添上一个减号 - , 后面跟参数值(文件名);
e.g. 实现对输入参数的分析: case
help()
{
cat
<< HELP
This is a generic
command
line parser demo.
USAGE EXAMPLE: cmdparser -l hello -f -- -somefile1 somefile2
HELP
exit
0
}
while
[ -n
"$1"
];
do
case
"$1"
in
-h) help;
shift
1;;
# function help is called
-f) opt_f=1;
shift
1;;
# variable opt_f is set
-l) opt_l=$2;
shift
2;;
# -l takes an argument -> shift by 2
--)
shift
;
break
;;
# end of options
-*)
echo
"error: no such option $1. -h for help"
;
exit
1;;
*)
break
;;
esac
done
echo
"opt_f is $opt_f"
echo
"opt_l is $opt_l"
echo
"first arg is $1"
echo
"2nd arg is $2"
>运行脚本: cmdparser -l hello -f -- -somefile1 somefile2;
>输出: opt_f is 1; opt_l is hello; first arg is -somefile1; 2nd arg is somefile2;
>脚本首先在所有输入命令行参数中进行循环, 将输入参数与case表达式进行比较, 如果匹配则配置一个变量并且移除该参数; 根据unix惯例, 首先输入的应该是包含减号的参数;
7 Shell脚本示例
一般编程步骤
任何优秀的脚本都应该有帮助和输入参数; 写一个框架脚本framework.sh, 包含大多数脚本需要的框架结构是一个好主意;
这样, 在开始编写新脚本时, 可以先执行以下命令: cp framework.sh myscript ; 然后再插入自己的函数; [节省时间, 规范代码]
二进制到十进制的转换
脚本b2d将二进制数转换为相应的十进制, 利用expr命令进行数学运算;
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091#!/bin/bash
# vim: set sw=4 ts=4 et:
help()
{
cat
<< HELP
b2d -- convert binary to decimal
USAGE: b2d [-h] binarynum
OPTIONS: -h help text
EXAMPLE: b2d 111010
will
return
58
HELP
exit
0
}
error()
{
# print an error and exit
echo
"$1"
exit
1
}
lastchar()
{
# return the last character of a string in $rval
if
[ -z
"$1"
];
then
# empty string
rval=
""
return
fi
# wc puts some space behind the output this is why we need sed:
numofchar=`
echo
-n
"$1"
|
sed
's/ //g'
|
wc
-c `
# now cut out the last char
rval=`
echo
-n
"$1"
|
cut
-b $numofchar`
}
chop()
{
# remove the last character in string and return it in $rval
if
[ -z
"$1"
];
then
# empty string
rval=
""
return
fi
# wc puts some space behind the output this is why we need sed:
numofchar=`
echo
-n
"$1"
|
wc
-c |
sed
's/ //g'
`
if
[
"$numofchar"
=
"1"
];
then
# only one char in string
rval=
""
return
fi
numofcharminus1=`
expr
$numofchar
"-"
1`
# now cut all but the last char:
rval=`
echo
-n
"$1"
|
cut
-b -$numofcharminus1`
#原来的 rval=`echo -n "$1" | cut -b 0-${numofcharminus1}`运行时出错.
#原因是cut从1开始计数,应该是cut -b 1-${numofcharminus1}
}
while
[ -n
"$1"
];
do
case
$1
in
-h) help;
shift
1;;
# function help is called
--)
shift
;
break
;;
# end of options
-*) error
"error: no such option $1. -h for help"
;;
*)
break
;;
esac
done
# The main program
sum
=0
weight=1
# one arg must be given:
[ -z
"$1"
] && help
binnum=
"$1"
binnumorig=
"$1"
while
[ -n
"$binnum"
];
do
lastchar
"$binnum"
if
[
"$rval"
=
"1"
];
then
sum
=`
expr
"$weight"
"+"
"$sum"
`
fi
# remove the last position in $binnum
chop
"$binnum"
binnum=
"$rval"
weight=`
expr
"$weight"
"*"
2`
done
echo
"binary $binnumorig is decimal $sum"
#
>使用的算法是十进制和二进制数权值(1 2 4 8 16...), e.g. 二进制10 -> 0 * 1 + 1 * 2 = 2;
>lastchar函数得到单个的二进制数, 该函数使用wc -c计算字符个数, 然后用cut命令取出末尾一个字符; chop函数的功能是移除最后一个字符;
文件循环拷贝
e.g. 将所有发出的邮件保存到一个文件中; 过了一段时间后这个文件可能会变很大以至于文件访问速度变慢; 脚本rotatefile可以重命名邮件保存文件为outmail.1, 把原来的outmail.1变成outmail.2等等...
#!/bin/bash
# vim: set sw=4 ts=4 et:
ver=
"0.1"
help()
{
cat
<< HELP
rotatefile -- rotate the
file
name
USAGE: rotatefile [-h] filename
OPTIONS: -h help text
EXAMPLE: rotatefile out
This will e.g rename out.2 to out.3, out.1 to out.2, out to out.1[BR]
and create an empty out-
file
The max number is 10
version $ver
HELP
exit
0
}
error()
{
echo
"$1"
exit
1
}
while
[ -n
"$1"
];
do
case
$1
in
-h) help;
shift
1;;
--)
break
;;
-*)
echo
"error: no such option $1. -h for help"
;
exit
1;;
*)
break
;;
esac
done
# input check:
if
[ -z
"$1"
] ;
then
error
"ERROR: you must specify a file, use -h for help"
fi
filen=
"$1"
# rename any .1 , .2 etc file:
for
n
in
9 8 7 6 5 4 3 2 1;
do
if
[ -f
"$filen.$n"
];
then
p=`
expr
$n + 1`
echo
"mv $filen.$n $filen.$p"
mv
$filen.$n $filen.$p
fi
done
# rename the original file:
if
[ -f
"$filen"
];
then
echo
"mv $filen $filen.1"
mv
$filen $filen.1
fi
echo
touch
$filen
touch
$filen
>检测到用户提供了一个文件名之后, 先进行一个9到1的循环, 文件名.9 重命名为 文件名.10, .8 -> .9 ... 循环结束后把原始文件命名为 文件名.1 ,同时创建一个和原始文件同名的空文件(touch $filen);
脚本调试
最简单的调试方法是使用echo命令; [print流派...] 可以在任何怀疑会出错的地方用echo打印变量值, 大部分shell程序员花费80%时间用于调试; shell脚本的好处在于无需重新编译, 插入echo命令也不需要多少时间;
shell也有调试模式, 如果脚本strangescript出错, 可以使用:
1sh -x strangescript
>执行脚本, 同时显示所有变量的值; [每一步输出]
shell还有不执行脚本只检查语法的模式:
sh -n your_script
>这个命令会返回所有语法错误;
---The End---
refer to http://wiki.ubuntu.com.cn/Shell%E7%BC%96%E7%A8%8B%E5%9F%BA%E7%A1%80