shell脚本编程基础
chapter 11 构建基本脚本
(等号为变量赋值时,变量,等号,值之间不能有空格)
引用变量时,要用美元符号,不然系统会将变量名当作字符串
将命令输出赋值给变量,(1 反引号字符(`)与~号在同一个键盘位置,2 $)
输出重定向 (命令 > 文件) (覆盖文件数据)(命令 >> 文件)(在文件尾追加数据)
输入重定向 (命令 < 文件) ,内联输入重定向(命令 << 数据)
管道连接(命令1 | 命令2 | ... | 命令n),(Linux系统同时运行这两个命令,在系统内部将它们连接起来,第一个命令产生输出的同时,输出会被立即送到第二个命令,数据传输不会用到任何中间文件或者缓冲区)
数学运算(加减乘除等)在方括号内,如var4=$[$var1 * ($var2 - $var3)],(只支持整数运算)
要用内建bash计算机来进行浮点运算(命令 bc进入,输入quit退出)(浮点运算要设置内建变量scale,其代表运算结果小数点保留位数)
查看退出状态码,echo $?。exit + 一个数,可以自己指定退出状态码,但是这个数字最大只能是255
chapter 12 使用结构化命令
如果if后面的命令的退出状态码是0,执行then部分
if 后不能接命令之外的条件判断,其他条件用test,或者[]
if command
then
commands
elif test condition
then
commands
elif [condition]
then
commands
else
commands
fi
数值大小比较,n1 -eq(相等),-ne(不等),-gt(大于),-lt(小于),-ge(大于等于),-le(小于等于) n2
在test数值大小比较中,不能使用浮点值。
字符串比较
str1 =,!=,<,> str2(大于小于号必须转义,否则会被当作重定向符号)
-n(检查字符串长度是否非0),-z(检查字符串长度是否为0) str1
#!/bin/bash
val1=baseball
val2=hockey
if [ $val1 \> $val2 ]
then
echo "$val1 is greater than $val2"
else
echo "$val1 is less than $val2"
fi
文件比较,检查文件是否可读可写,是否是目录等
符合条件测试,允许&&和||
if else 里允许双括号,也就是((a++, !, ~, **, <<, >>, &, |, &&, ||)),这些逻辑运算和位运算等
也允许双方括号,也就是[[模式匹配(正则表达式)]]
chapter 13 更多的结构化命令
for 循环
list="Alab Alas Ariz Arka Colo"
list=$list" Conn" #向字符串尾部添加文本
IFS.OLD=$IFS
IFS=$'\n'
for var in $(cat $file)
do
commands
done > text.txt
IFS=$IFS.OLD
...
for 循环用空格分隔单词,若有单词内包含',或者空格,可以用双引号把这个单词的所有内容括起来,或者为'符号转义
环境变量IFS定义了bash shell用作字符串分割符的一系列字符。默认情况下是空格,制表符,换行符。为了方便操作,可在脚本中手动设置IFS,来避免多种分隔符带来的不便。
while 循环
input="users.csv"
while IFS=',' read -r userid name #test commands#(也可以用[])
do
echo "adding $userid"
useradd -c "$name" -m $userid
done < "$input"
until循环,commands返回值为0时退出,和while相反
until test commands
do
commands
done
break和continue不单单可以跳出当前循环,也可以通过break/continue + 数字来跳过外部循环
done 后加上 > file可以将循环输出重定向到文件
chapter 14 处理用户输入
$ + 数字,来获取命令行参数。./test1 1 2 3。可以用$1,$2,$3来获取,更多的,用$(10)这样的形式获取(这种形式也可以用来获取选项,如test.sh -a)
$0可以获取脚本名
$#可以获取脚本运行时携带的命令行参数个数
$*获取所有命令行参数作为一个字符串
$@获取所有命令行参数作为多个值,可用循环遍历
shift命令,将所有命令行参数向左移,最左(除了$0)被删除,这样用$1就能够遍历所有参数。也可以shift后加数字,代表移动多个单元
命令行选项和参数合用,使用 -- 字符分割
命令test16.sh -c test4 -a -b -- test1 test2 test3
#!/bin/bash
set -- $(getopt -q ab:cd "$@")
echo
while[ -n "$1" ]
do
case "$1" in
-a) echo "Found the -a option" ;;
-b) echo "Found the -b option" ;;
-c) param="$2"
echo "Found the -c option"
shift ;;
--) shift
break;;
*) echo "$1 is not an option" ;;
esac
shift
done
count=1
for param in $@
do
echo "Parameter #$count: $param"
count=$[ $count + 1 ]
done
getopt处理合并选项
set命令的选项之一是 -- ,它会将命令行参数替换成set命令的命令行值。
该方法会将原始脚本的命令行参数传递给getopt命令,之后将getopt命令的输出传给set命令
但是getopt命令并不擅长处理带空格和引号的参数值。它会将空格作为分隔符而不是根据双引号将二者当作一个参数。
getopts命令则有改进
解析命令行时会移除开头的单破折线,并且可以处理带空格和引号的参数值
它有两个环境变量
OPTARG,选项跟的参数值
OPTIND,参数列表中getopts正在处理的参数位置
#!/bin/bash
echo
while getopts :ab:c opt
do
case "$opt" in
a) echo "Found the -a option" ;;
b) echo "Found the -b option, with value $OPTARG" ;;
c) echo "Found the -c option";;
*) echo "Unknown option: $opt";;
esac
done
shift $[ $OPTIND - 1 ]
echo
count=1
for param in "$@"
do
echo "Parameter $count: $param"
count=$[ $count + 1 ]
done
read命令从标准输入输出中接受输入,如(read -p "Enter your name: " first last)
-t 选项可以指定read命令等待输入的时间,时间超时则read返回非0退出状态码并且继续执行脚本
或者使用-n + 数字来指定read命令可接受最多的字符
-s选项可以避免输入数据显示在屏幕上,如输入密码的时候
从文件中读取数据
cat read | while read lind
chapter 15 呈现数据
文件描述符,0(STDIN),1(STDOUT),2(STDERR)
(shell对于错误消息的处理和普通输出是分开的,通过STDERR而不是STDOUT处理)
重定向错误信息到文件举例
ls -al badfile 2> test4(这里的2代表STDERR,必须紧跟>)
如果想重定向错误和正常数据,必须用两个>
如 ls -al test test2 test3 badtest 2> test6 1> test7
如果想把脚本中的输出重定向到STDERR,那么需要加&
如 echo "This is an error" >&2
exec命令可以进行永久重定向
#!/bin/bash
exec 0< testfile
exec 2>testerror
echo "This is the start of the script"
echo "now redirecting all output to another location"
exec 1>testout
echo "This output should go to the testout file"
echo "but this should go to the testerror file" >&2
(尽管STDOUT被重定向了,但是echo仍可以发送给STDERR)
lsof可以列出整个linux系统打开的所有文件描述符
可以对null文件进行重定向来实现很多便利的操作
mktemp可以用来创建临时文件(mktemp testing.XXXXXX(六个X会被替换成6个字符来保证文件名不重复)),他的返回值是这个文件的名字,来方便在脚本中直接使用。
(-t,-d)
tee命令可以将STDIN过来的数据同时发往两处(date | tee -a testfile)
#!/bin/bash
outfile='members.sql'
IFS=','
while read lname fname address city state zip
do
cat >> $outfile << EOF
INSERT INTO members (lname,fname,address,city,state,zip) VALUES ('$lname','$fname','$address','$city','$state','$zip')
EOF
done < ${1}
chapter 16 控制脚本
trap命令:捕获信号
trap -- SIGINT删除捕获
可以使用后台模式运行脚本,在后台模式,进程运行不会和STDIN,STDOUT,STDERR关联,但是仍会使用中端显示器来显示STDOUT和STDERR消息,但是最好重定向,不然太混乱。
后台模式运行(./test.sh &,返回 [作业号] PID)
nohup命令可以让以后台模式运行的程序,在推出了终端会话后,仍然保持运行。(nohup ./test1.sh &)(脚本忽略关闭终端会话时发过来的SIGHUP信号)
jobs -l 命令查看作业运行情况
bg命令可以以后台模式重启作业
fg命令可以以前台模式重启作业
nice命令允许设置命令启动时的调度优先级,(-20(最高)到+19(最低))(nice -n 10 ./test4.sh > test4.out &)(普通系统用户只能把优先级调低,调高要用root)
renice命令更新当前进程的优先级
at命令可以在指定时间运行脚本
cron程序用来定期执行脚本(min hour dayofmonth month dayofweek command)(15 10 * * * command 每天10:15)
(15 16 * * 1 command 每周一16:15)(00 12 1 * * command 每个月第一天12:00)
(000 12 * * * if [`date +%d -d tomorrow` = 01 ] ; then ; command)(每个月最后一天)
(15 10 * * * /home/rich/test4.sh > test4out )
crontab来处理cron时间表