Shell编程
shell 脚本实质上为文本文件
shell基本语法
执行方式
$ sh < program.sh
$ sh program.sh
$ ./program.sh
需要赋予执行权限
信息流
默认有三个信息流
- 文件描述符0
stdin
-> 键盘 - 文件描述符1
stdout
-> 显示器 - 文件描述符2
stderr
-> 显示器
可以重定向
-
>
输出重定向 如$ cat demo.sh > result.sh
会删除result.sh的原有内容 -
>>
输出重定向 将输出结果追加到文件末尾 -
<
输入重定向 如sh < demo.sh
-
>&
错误流重定向 不同的shell不同,好像没有错误也会重定向额
管道线处理
-
|
程序输入作为另一个程序输出 如$ ls -l | wc -l
(计算行数) -
;
多个命令顺序执行(单线程) &
后台执行命令,关了命令行也会继续执行(在命令行末尾输入)&&
左边命令为真时执行右边命令||
左边命令为假时执行右边命令
Shell变量定义
变量名 ^[a-zA-Z_][a-zA-Z0-9_]*
类型 字符串(only)
清除变量unset var
,相当于delete
吧
如何调用(引用)变量
在变量名前加$
如$var
也可以用{}
如${var}
$
转义后不表示引用,如\$var
输出$var
三种引号
-
' '
单引号,屏蔽任意字符的特殊含义 也就是说,里面的东西全当成字符串,不进行任何处理 -
" "
双引号,屏蔽大部分字符的特殊含义 除了$
美元符号,' '
单引号,\
下划线 -
``反引号,里面的命令可以执行,且只能为命令
变量定义、调用、赋值例子
赋值时不用加$
#!/bin/sh
var=hello
echo '$var='$var #$var=hello
echo '${var}'=$var #${var}=hello
echo '"$var"'="$var" #"$var"=hello
echo '"\$var"'="\$var" #"\$var"=$var
echo 'date is `date`' #date is `date`
echo "date is `date`" #date is Tue May 12 11:02:28 CST 2015
name=`I am whoami` #./shelldemo.sh: 1: ./shelldemo.sh: I: not found
echo $name
变量作用域
以默认的变量声明方式,声明的变量,其作用域是局部的,只能在该shell进程中起作用
用export var
可以将其声明为全局变量
finalize@junjie:/$ var=hello
finalize@junjie:/$ echo $var
hello
finalize@junjie:/$ sh
$ echo $var
$ exit
finalize@junjie:/$ echo $var
hello
finalize@junjie:/$ export var
finalize@junjie:/$ sh
$ echo $var
hello
$ exit
finalize@junjie:/$ echo $var
hello
ShellScript
行首
#!/bin/sh
指定解释器
系统默认内置变量
$#
传递到脚本的参数个数$*
以一个单字符串显示所有向脚本传递的参数$@
与$*相同,但是以多个字符串显示所有向脚本传递的参数,每个字符串为一个参数$$
脚本运行的当前进程ID号$!
后台运行的最后一个进程的进程ID号$-
显示shell使用的当前选项,与set命令功能相同;$?
显示最后命令的退出状态。0表示没有错误,其他任何值表明有错误;
shelldemo.sh
#!/bin/sh
echo '$# '$#
echo '$* '$*
echo '$$ '$$
echo '$! '$!
echo '$@ '$@
echo '$- '$-
echo '$? '$?
output
finalize@junjie:~$ ./shelldemo.sh hello world
$# 2
$* hello world
$$ 5690
$!
$@ hello world
$-
$? 0
条件判断与计算
测试文件状态
语法 test condition
or [ condition ]
(括号两边有空格)
condition:
( EXPRESSION )
EXPRESSION is true
! EXPRESSION
EXPRESSION is false
EXPRESSION1 -a EXPRESSION2
both EXPRESSION1 and EXPRESSION2 are true
EXPRESSION1 -o EXPRESSION2
either EXPRESSION1 or EXPRESSION2 is true
-n STRING
the length of STRING is nonzero
STRING equivalent to -n STRING
-z STRING
the length of STRING is zero
STRING1 = STRING2
the strings are equal
STRING1 != STRING2
the strings are not equal
INTEGER1 -eq INTEGER2
INTEGER1 is equal to INTEGER2
INTEGER1 -ge INTEGER2
INTEGER1 is greater than or equal to INTEGER2
INTEGER1 -gt INTEGER2
INTEGER1 is greater than INTEGER2
INTEGER1 -le INTEGER2
INTEGER1 is less than or equal to INTEGER2
INTEGER1 -lt INTEGER2
INTEGER1 is less than INTEGER2
INTEGER1 -ne INTEGER2
INTEGER1 is not equal to INTEGER2
FILE1 -ef FILE2
FILE1 and FILE2 have the same device and inode numbers
FILE1 -nt FILE2
FILE1 is newer (modification date) than FILE2
FILE1 -ot FILE2
FILE1 is older than FILE2
-b FILE
FILE exists and is block special
-c FILE
FILE exists and is character special
-d FILE
FILE exists and is a directory
-e FILE
FILE exists
-f FILE
FILE exists and is a regular file
-g FILE
FILE exists and is set-group-ID
-G FILE
FILE exists and is owned by the effective group ID
-h FILE
FILE exists and is a symbolic link (same as -L)
-k FILE
FILE exists and has its sticky bit set
-L FILE
FILE exists and is a symbolic link (same as -h)
-O FILE
FILE exists and is owned by the effective user ID
-p FILE
FILE exists and is a named pipe
-r FILE
FILE exists and read permission is granted
-s FILE
FILE exists and has a size greater than zero
-S FILE
FILE exists and is a socket
-t FD file descriptor FD is opened on a terminal
-u FILE
FILE exists and its set-user-ID bit is set
-w FILE
FILE exists and write permission is granted
-x FILE
FILE exists and execute (or search) permission is granted
Except for -h and -L, all FILE-related tests dereference symbolic
links. Beware that parentheses need to be escaped (e.g., by back‐
slashes) for shells. INTEGER may also be -l STRING, which evaluates to
the length of STRING.
括号的使用
#[]中的分号不可少,{}两边空格不可少
[ -f main.c ] && { pwd; ls; rm main.c -f;}
#()两边可以没有空格
[ -f main.c ] && (pwd ;ls ;rm main.c -f)
[ -f main.c ] && {
pwd
ls
rm main.c -f
}
expr计算表达式的值
符号需要用转义字符,如[
expr $x > 20= 0 ] && echo ‘$x = ’ $x is less than 20
ARG1 | ARG2
ARG1 if it is neither null nor 0, otherwise ARG2
ARG1 & ARG2
ARG1 if neither argument is null or 0, otherwise 0
ARG1 < ARG2
ARG1 is less than ARG2
ARG1 <= ARG2
ARG1 is less than or equal to ARG2
ARG1 = ARG2
ARG1 is equal to ARG2
ARG1 != ARG2
ARG1 is unequal to ARG2
ARG1 >= ARG2
ARG1 is greater than or equal to ARG2
ARG1 > ARG2
ARG1 is greater than ARG2
ARG1 + ARG2
arithmetic sum of ARG1 and ARG2
ARG1 - ARG2
arithmetic difference of ARG1 and ARG2
ARG1 * ARG2
arithmetic product of ARG1 and ARG2
ARG1 / ARG2
arithmetic quotient of ARG1 divided by ARG2
ARG1 % ARG2
arithmetic remainder of ARG1 divided by ARG2
STRING : REGEXP
anchored pattern match of REGEXP in STRING
match STRING REGEXP
same as STRING : REGEXP
substr STRING POS LENGTH
substring of STRING, POS counted from 1
index STRING CHARS
index in STRING where any CHARS is found, or 0
length STRING
length of STRING
+ TOKEN
interpret TOKEN as a string, even if it is a
keyword like 'match' or an operator like '/'
( EXPRESSION )
value of EXPRESSION
Beware that many operators need to be escaped or quoted for shells.
Comparisons are arithmetic if both ARGs are numbers, else lexicographi‐
cal. Pattern matches return the string matched between \( and \) or
null; if \( and \) are not used, they return the number of characters
matched or 0.
Exit status is 0 if EXPRESSION is neither null nor 0, 1 if EXPRESSION
is null or 0, 2 if EXPRESSION is syntactically invalid, and 3 if an
error occurred.
流程控制
条件结构 if-then-elif-else-fi
注意if[ condition ]后面有逗号
if [ -d mdir ] ; then
echo 'this is a dir'
elif [ -f mdir ] ; then
echo 'this is a regular file'
else
echo 'unknown file'
fi
case结构
case $1 in
"start")
echo "start"
date
;;
"stop")
echo "stop"
date
;;
esac
while循环结构
#!/bin/sh
sum=0;
index=0;
while [ $index -le 100 ]
do
#加号之间一定要有空格,否则就成了字符串了"0+0"
sum=$(expr $sum + $index)
index=$(($index+1))
done
echo "1+2+3+...+100="$sum
output
finalize@junjie:~$ ./manexpr
1+2+3+...+100=5050
for循环结构
#!/bin/sh
for file in /home/finalize/*
do
if [ -d $file ] ; then
echo $file
fi
done
output
finalize@junjie:~$ ./manexpr
/home/finalize/Desktop
/home/finalize/Documents
/home/finalize/Downloads
/home/finalize/Music
/home/finalize/Pictures
/home/finalize/Public
/home/finalize/Softwares
/home/finalize/Templates
/home/finalize/Videos
/home/finalize/git
/home/finalize/workspace
finalize@junjie:~$
break,continue,exit
break,continue在while和for中使用。exit终止程序,exit 0
表示程序正常退出
函数
函数声明
funcname(){
}
funcname()
{
}
函数调用与参数传递
- 调用
funcname
- 传参
funcname arg1 arg2
- 获取参数
$0 $1 $2 $* $@
$0
表示文件名(相对路径)
shell script追踪与调试
- n : 不要执行script,仅查询语法错误
- v : 输出script的源码,遇到输出命令时,则打印到屏幕
-
x : 将使用到的script输出到屏幕上,也就是调用到的其它命令
-
-n noexec If not interactive, read commands but do not execute them. This is useful for checking the syntax of shell scripts.
-
-u nounset Write a message to standard error when attempting to expand a variable that is not set, and if the shell is not interactive, exit immediately.
-
-v verbose The shell writes its input to standard error as it is read. Useful for debugging.
-
-x xtrace Write each command to standard error (preceded by a ‘+ ’) before it is executed. Useful for debuging.
finalize@junjie:~$ cat shdemo
#!/bin/sh
echo `date`)
echo `whoami`
echo `pwd`
echo "haha"
finalize@junjie:~$ sh -n shdemo
shdemo: 3: shdemo: Syntax error: ")" unexpected
finalize@junjie:~$ sh -v shdemo
#!/bin/sh
echo `date`
Tue May 12 16:04:44 CST 2015
echo `whoami`
finalize
echo `pwd`
/home/finalize
echo "haha"
haha
finalize@junjie:~$ sh -x shdemo
+ date
+ echo Tue May 12 16:05:15 CST 2015
Tue May 12 16:05:15 CST 2015
+ whoami
+ echo finalize
finalize
+ pwd
+ echo /home/finalize
/home/finalize
+ echo haha
haha
finalize@junjie:~$
对于有循环的script,使用sh -v 时
finalize@junjie:~$ cat manexpr
#!/bin/sh
sum=0;
add(){
sum=$(($1+$2))
}
echo "xixi"
for i in `seq 100`
do
add $sum $i
done
echo $sum
finalize@junjie:~$ sh -v manexpr
#!/bin/sh
sum=0;
add(){
sum=$(($1+$2))
}
echo "xixi"
xixi
for i in `seq 100`
do
add $sum $i
done
echo $sum
5050
finalize@junjie:~$