不同的命令可接受的命令行格式或有不同,一般情况下,一个标准的命令行格式为如下所列:
command-name options argument
若从技术细节来看,shell 会依据 IFS(Internal Field Seperator) 将 command line 所输入的文字给拆解为"字段"(word)。
然后再针对特殊字符(meta)先作处理,最后再重组整行 command line 。
(注意:请务必理解上两句话的意思,我们日后的学习中会常回到这里思考。)
其中的 IFS 是 shell 预设使用的字段分隔符,可以由一个及多个如下按键组成:
* 空格键(White Space)
* 表格键(Tab)
* 回车键(Enter)
首先己说说语法里的配对现象:
if --fi
case--esac
do--done
1、变量
定义一个变量:varname=value,等号两边不能有空格,否则会被解释成命令。
变量分为本地变量和环境变量。本地变量只存在于当前的shell进程,而环境变量
可以从当前进程传递给fork出来的子进程。printenv可以打印出当前进程的环境变量。
用export可以将本地变量导出成环境变量。用unset可以删除变量。
2、命令代换
可以用`和$()进行命令代换。如:
birth=`date`或birth=$(date)
3、算术代换$(())
var=45
echo $(($var+3))
4、转义字符/
这个/没什么好说的,各种语言都有,不过在shell里有个特殊的地方。
其中“-”加上转义字符也不行,如果要创建一个-hell的文件,你需要这么做
touch ./-hello
5、交互登录的shell
就是输入用户名和密码后得到的shell。
进入登录shell后会执行一系列文件:
/etc/profile、~/.bash_profile、~/.bash_login、~/.profile
在退出时候要执行~/.bash_logout
6、交互非登录的shell
在图形界面打开一个终端或者在登陆shell中执行bash命令,就得到一个交互非登录的shell。
这种shell在启动时自动执行~/.bashrc。
一般在bashrc里面设置本地变量、函数、alias。
7、非交互启动的shell
为执行脚本而fork出来的是非交互shell。
它会执行BASH_ENV这个环境变量指定的文件。
if [ -n "$BASH_ENV" ]; then . "$BASH_ENV"; fi
8、条件测试
可以用test或[]进行条件测试,如果测试结果为真就返回0,如果为假就返回1。
测试两个数的大小:
- $ VAR=2
- $ test $VAR -gt 1
- $ echo $?
- 0
- $ test $VAR -gt 3
- $ echo $?
- 1
- $ [ $VAR -gt 3 ]
- $ echo $?
- 1
[是一个命令,传递给它的参数都用空格分开。
bash 的 test 目前支援的測試對像只有三種:
* string:字串,也就是純文字。
* integer:整數( 0 或正整數,不含負數或小數點)。
* file:文件。
請初學者一定要搞清楚這三者的差異,因為 test 所用的 expression 是不一樣的。
以 A=123 這個變量為例:
* [ "$A" = 123 ]:是字串的測試,以測試 $A 是否為 1、2、3 這三個連續的"文字"。
* [ "$A" -eq 123 ]:是整數的測試,以測試 $A 是否等於"一百二十三"。
* [ -e "$A" ]:是關於文件的測試,以測試 123 這份"文件"是否存在。
常见的测试命令如下:
[ -d dir ] :如果dir存在,返回真
[ -f filename ] :如果filename这个文件存在,就返回真
[ -z string ] :如果string为空返回真
[ -n string ] :如果string不为空返回真
[ string1 = string2 ] :如果相等返回真
[ string1 != string2 ] :如果不相等返回真
[ arg1 OP arg2 ] :OP可以是-gt/-lt/-ge/-le/-eq/-ne中的任意一个。对整数的测试
比较字符写法:
-eq 等于
-ne 不等于
-gt 大于
-lt 小于
-le 小于等于
-ge 大于等于
以上是对整数的测试字符,
下面是对字符串的:
-z 空串
= 两个字符相等
!= 两个字符不等
-n 非空串 (測試 string 長度大於 0)
其他语言常用的!、and、or在shell里面这么表示:
同時,test 也允許多重的覆合測試:
* expression1 -a expression2 :當兩個 exrepssion 都為 true ,才送出 0 ,否則送出非 0 。
* expression1 -o expression2 :只需其中一個 exrepssion 為 true ,就送出 0 ,只有兩者都為 false 才送
[ ! exp ]
[ exp1 -a exp2 ]
[ exp1 -o exp2 ]
举个例子:
[ -d test -a “$var”="abc" ]
其中$var一般要用引号引起来,否则容易引起错误。原因是,如果var为空的话,这句会被
解释成这样:[ -d test -a ="abc" ],这显然有语法错误,但是加上引号就会被解释成这样:
[ -d test -a ""="abc" ]这样无论如何都不会有语法错误了。
9、if语句
if语句常常包含以下关键词:if、then、else、elif、fi。
- if [ -f ~/.bashrc ]; then
- . ~/.bashrc
- fi
- if :; then echo "always true"; fi
if [ -f ~/.bashrc ]是一条,then . ~/.bashrc、fi各是一条。如果两条写在一块,就要用“;”分割。
:是一个空命令,表示什么也不执行。
shell的if与c语言if的功能上的区别
| |
0为真,走then | |
必须:if [ i –ne 0 ] 但支持字符串变量直接if if [ str ] 如果字符串非0 | if (i ) |
比较两个字符串是否相等的办法是:
if [ "$test"x = "test"x ]; then
这里的关键有几点:
1 使用单个等号
2 注意到等号两边各有一个空格:这是unix shell的要求
3 注意到"$test"x最后的x,这是特意安排的,因为当$test为空的时候,上面的表达式就变成了x = testx,显然是不相等的。而如果没有这个x,表达式就会报错:[: =: unary operator expected
注意: if [ "$test"x = "test"x ] "$test"x = "test"x 前后都要有空格
10、case语句
case语句 :它能够把变量的内容与多个模板进行匹配,再根据成功匹配的模板去决定应该执行哪部分代码。
使用格式:
case 匹配母板 in
模板1 [ | 模板2 ] … ) 语句组 ;;
模板3 [ | 模板4 ] … ) 语句组 ;;
esac
case语句的匹配是从上往下地匹配顺序。因此,case语句编写的原则是从上往下,模板从特殊到普通。在C语言里,case语句中有default模板,而
在shell程序设计中,可能将模板写成*,就可以完成相同的功能。
- #! /bin/sh
- echo "Is it morning? Please answer yes or no."
- read YES_OR_NO
- case "$YES_OR_NO" in
- yes|y|Yes|YES)
- echo "Good Morning!";;
- [nN]*)
- echo "Good Afternoon!";;
- *)
- echo "Sorry, $YES_OR_NO not recognized. Enter yes or no."
- exit 1;;
- esac
- exit 0
11、for/do/done
for 无$变量 in字符串
do
done
- #! /bin/sh
- for FRUIT in apple banana pear; do
- echo "I like $FRUIT"
- done
12、while/do/done
- #! /bin/sh
- echo "Enter password:"
- read TRY
- while [ "$TRY" != "secret" ]; do
- echo "Sorry, try again"
- read TRY
- done
13、位置参数和特殊变量
$0:文件名 相当于C语言main
函数的argv[0]
$#:参数个数
$1,$2 这些称为位置参数(Positional Parameter),相当于C语言main函数的argv[1]、argv[2]...
$@:参数列表,不包括$0 表示参数列表"$1" "$2" ...,例如可以用在for循环中的in后面。
$?:上一次命令执行是否成功的标志 上一条命令的Exit Status
$$:进程id
14、函数
调用函数时可以传递任意个参数,在函数内提取参数用$0/$1....
下面这个脚本可以一次创建多个目录,各目录名通过命令行参数传入,脚本逐个测试各目录是否存在,如果目录不存在,首先打印信息然后试着创建该目录。
- #! /bin/sh
- is_directory()
- {
- DIR_NAME=$1
- if [ ! -d $DIR_NAME ]; then
- return 1
- else
- return 0
- fi
- }
- for DIR in "$@"; do
- if is_directory "$DIR"
- then :
- else
- echo "$DIR doesn't exist. Creating it now..."
- mkdir $DIR > /dev/null 2>&1
- if [ $? -ne 0 ]; then
- echo "Cannot create directory $DIR"
- exit 1
- fi
- fi
- done
15 select 表达式是一种bash的扩展应用,尤其擅长于交互式使用。用户可以从一组不同的值中进行选择。
select var in ... ; do
break
done
例如 :
#!/bin/sh
echo "What is your favourite OS?"
select var in "Linux" "Gnu Hurd" "Free BSD" "Other"; do
break
done
echo "You have selected $var"
结论 :
linux-bvhu:/home # ./select.sh
What is your favourite OS?
1) Linux
2) Gnu Hurd
3) Free BSD
4) Other
#? 1 //选择数字
You have selected Linux
16.
&& 與 || 都是用來"組建"多個 command line 用的:
* command1 && command2 :其意思是 command2 只有在 RV 為 0 (true) 的條件下執行。
* command1 || command2 :其意思是 command2 只有在 RV 為非 0 (false) 的條件下執行。
17、脚本的调试
sh -x ./test.sh:这样可以将执行的每一条命令和结果打印出来。