2 Shell 的默认赋值是字符串赋值
var=1
var=$var+1
echo $var
打印出来的是1+1而不是2。
3 [ -f "somefile" ] :判断是否是一个文件
[ -x "/bin/ls" ] :判断/bin/ls是否存在并有可执行权限
[ -n "$var" ] :判断$var变量是否有值
[ "$a" = "$b" ] :判断$a和$b是否相等
4 if 语句:
if ...; then
...
elif ...; then
...
else
...
if
下面是一个简单的if语句:
#!/bin/bash
if [ ${SHELL} = "/bin/bash" ] ; then
echo "your login shell is the bash (bourne again shell)"
else
echo "your login shell is not bash but ${SHELL}"
fi
5 case 语句
case表达式可以用来匹配一个给定的字符串,而不是数字(可别和C语言里的switch...case混淆)。
case ... in
...)
do something here ;;
esac
file命令可以辨别出一个给定文件的文件类型,如:file lf.gz,其输出结果为:
lf.gz: gzip compressed data, deflated, original filename,
last modified: Mon Aug 27 23:09:18 2001, os: Unix
我们利用这点写了一个名为smartzip的脚本,该脚本可以自动解压bzip2, gzip和zip 类型的压缩文件:
#!/bin/bash
ftype="$(file "$1")"
case "$ftype" in
"$1: Zip archive"*)
unzip "$1" ;;
"$1: gzip compressed"*)
gunzip "$1" ;;
"$1: bzip2 compressed"*)
bunzip2 "$1" ;;
*) echo "File $1 can not be uncompressed with smartzip";;
esac
你可能注意到上面使用了一个特殊变量$1,该变量包含有传递给该脚本的第一个参数值。也就是说,当我们运行:
smartzip articles.zip
$1 就是字符串 articles.zip。
6 Bash只提供一维数组,并且没有限制数组大小
7 对数组元素赋值
对数组元素赋值的一般形式是:数组名[下标]=值,例如:
$ city[0]=Beijing $ city[1]=Shanghai $ city[2]=Tianjin
一个数组的各个元素可以利用上述方式一个元素一个元素地赋值,也可以组合赋值。定义一个数组并为其赋初值的一般形式是:
数组名=(值1 值2 ... 值n)
其中,各个值之间以空格分开。例如:
$ A=(this is an example of shell script) $ echo ${A[0]} ${A[2]} ${A[3]} ${A[6]} this an example script $ echo ${A[8]}
由于值表中初值共有 7 个,所以 A 的元素个数也是 7 。 A[8] 超出了已赋值的数组 A 的范围,就认为它是一个新元素,由于预先没有赋值,所以它的值是空串。
若没有给出数组元素的下标,则数组名表示下标为 0 的数组元素,如 city 就等价于 city[0] 。
8 如果要列出数组中的所有元素,使用*或@作下标
9 获取数组元素的个数
$ echo ${#A[*]}
10 数值比较中常见的比较符
= -eq
!= -ne(not equal)
> -gt(greater than)
>= -ge(greater than or equal)
< -lt(less than)
<= -le
11 测试文件属性的常见参数
-r; -w; -x; -f; -d
12 字符串长度属性
-z(字符串长度为零)
-n(非零)
13 条件测试命令 test
语法:test 表达式 如果表达式为真,则返回真,否则,返回假。
$ test var1 -gt var2
$ test -r filename
$ test -z s1 如果串 s1 长度为零,返回真。
14 有限循环命令for...in...
语法:
for 变量名 in 字符串表 do 命令表 done
举例:
FILE="test1.c myfile1.f pccn.h" for i in $FILE do cd ./tmp cp $i $i.old echo "$i copied" done
for var in sss
sss是串行,串行是一些字符串的组合。for...in...的运作方式是把sss中的元素依次取出放入变量var中,并执行do和done之间的命令
15 判断字符的类型
范例:数字或者数字组合
能够返回结果,即程序退出状态是0,说明属于这种类型,反之不然
$ i=5;j=9423483247234; $ echo $i | grep [0-9]* 5 $ echo $j | grep [0-9]* 9423483247234 $ echo $j | grep [0-9]* >/dev/null $ echo $? 0
范例:字符组合(小写字母、大写字母、两者的组合)
$ c="A"; d="fwefewjuew"; e="fewfEFWefwefe" $ echo $c | grep [A-Z] A $ echo $d | grep "[a-z]*" fwefewjuew $ echo $e | grep "[a-zA-Z]*" fewfEFWefwefe
字母和数字的组合
$ ic="432fwfwefeFWEwefwef" $ echo $ic | grep "[0-9a-zA-Z]*" 432fwfwefeFWEwefwef
范例:空格或者 Tab 键等
$ echo " " | grep " " $ echo -e "\t" | grep "[[:space:]]" #[[:space:]]会同时匹配空格和TAB键 $ echo -e " \t" | grep "[[:space:]]" $ echo -e "\t" | grep "<tab>" #<tab>为在键盘上按下TAB键,而不是字符<tab>
范例:匹配邮件地址
$ echo "test2007@lzu.cn" | grep "[0-9a-zA-Z\.]*@[0-9a-zA-Z\.]" test2007@lzu.cn
16 /dev/null 和 /dev/zero 是非常有趣的两个设备,它们都犹如一个黑洞,什么东西掉进去都会消失殆尽;后者则是一个能源箱,你总能从那里取到 0,直到你退出。
17 $* 和 $@ 的区别
$*
所有参数列表。如"$*"用「"」括起来的情况、以"$1 $2 … $n"的形式输出所有参数。
$@
所有参数列表。如"$@"用「"」括起来的情况、以"$1" "$2" … "$n" 的形式输出所有参数。
示例:
1 #!/bin/bash
2 #
3printf"The complete list is %s\n" "$*"
|
结果:
[Aric
@localhost ~]$ bashparams.sh 123456 QQ
The complete listis 123456 QQ
|
1 #!/bin/bash
2 #
3printf"The complete list is %s\n" "$@"
|
结果:
[Aric@localhost ~]$ bashparams.sh 123456 QQ
The complete listis 123456
The complete listis QQ
|
18 字符串的长度
范例:计算某个字符串的长度
即所有字符的个数[这计算方法是五花八门,择其优者而用之]
$ var="get the length of me" $ echo ${var} # 这里等同于$var get the length of me $ echo ${#var} 20 $ expr length "$var" 20 $ echo $var | awk '{printf("%d\n", length($0));}' 20 $ echo -n $var | wc -c 20
19 字符串操作_取子串
取子串的方法主要有两种:直接到指定位置求子串,字符匹配求子串。
范例:按照位置取子串
比如从什么位置开始,取多少个字符
$ var="get the length of me" $ echo ${var:0:3} get $ echo ${var:(-2)} # 方向相反 me $ echo `expr substr "$var" 5 3` #记得把$var引起来,否则expr会因为空格而解析错误 the $ echo $var | awk '{printf("%s\n", substr($0, 9, 6))}' length
awk 把 $var 按照空格分开为多个变量,依次为 $1,$2,$3,$4,$5
$ echo $var | awk '{printf("%s\n", $1);}' get $ echo $var | awk '{printf("%s\n", $5);}' me
范例:匹配字符求子串
用 Bash 内置支持求子串
$ echo ${var%% *} #从右边开始计算,删除最左边的空格右边的所有字符 get $ echo ${var% *} #从右边开始计算,删除第一个空格右边的所有字符 get the length of $ echo ${var##* } #从左边开始计算,删除最右边的空格左边的所有字符 me $ echo ${var#* } #从左边开始计算,删除第一个空格左边的所有字符 the length of me
可以这么理解 #和%是从左边还是右边开始计算的flag,${var#* },从左边开始计算,删除一个"*"和一个" "(空格);${var##* }从左边开始计算,删除n个"*"和" ";${var% *}从右边开始计算,删除一个" "和"*";${var%% *}从右边开始计算,删除n个" "和"*"
对于字符串的截取,实际上还有一些命令,如果 head,tail 等可以实现有意思的功能,可以截取某个字符串的前面、后面指定的行数或者字节数。例如:
$ echo "abcdefghijk" | head -c 4 abcd $ echo -n "abcdefghijk" | tail -c 4 hijk
20 字符串操作_查询字串
子串查询包括:返回符合某个模式的子串本身和返回子串在目标串中的位置。
范例:查询子串在目标串中的位置
貌似仅仅可以返回某个字符或者多个字符中字符第一次出现的位置
$ var="get the length of me" $ expr index "$var" t 3
awk 却能找出字串,match 还可以匹配正则表达式
$ echo $var | awk '{printf("%d\n", match($0,"the"));}' 5
21 字符串操作_子串替换
用 {} 运算符
$ var="get the length of me" $ echo ${var/ /_} #把第一个空格替换成下划线 get_the length of me $ echo ${var// /_} #把所有空格都替换成了下划线了 get_the_length_of_me
用 awk,awk 提供了转换的最小替换函数 sub 和全局替换函数 gsub,类似 / 和 //
$ echo $var | awk '{sub(" ", "_", $0); printf("%s\n", $0);}' get_the length of me $ echo $var | awk '{gsub(" ", "_", $0); printf("%s\n", $0);}' get_the_length_of_me
用 sed ,子串替换可是 sed 的特长
$ echo $var | sed -e 's/ /_/' #s <= substitude get_the length of me $ echo $var | sed -e 's/ /_/g' #看到没有,简短两个命令就实现了最小匹配和最大匹配g <= global get_the_length_of_me
sed 还有专门的插入指令,a 和 i,分别表示在匹配的行后和行前插入指定字符
$ echo $var | sed '/get/a test' get the length of me test $ echo $var | sed '/get/i test' test get the length of me
22 重定向
linux shell下常用输入输出操作符是:
1. 标准输入 (stdin) :代码为 0 ,使用 < 或 <<
2. 标准输出 (stdout):代码为 1 ,使用 > 或 >>
3. 标准错误输出(stderr):代码为 2 ,使用 2> 或 2>>
实例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
#将错误输出信息关闭掉
[chengmo@centos5 shell]$ls test.sh test1.sh 2>&-
test.sh
[chengmo@centos5 shell]$ls test.sh test1.sh 2>/dev/null
test.sh
#&[n] 代表是已经存在的文件描述符,&1 代表输出 &2代表错误输出 &-代表关闭与它绑定的描述符
#/dev/null 这个设备,是linux 中黑洞设备,什么信息只要输出给这个设备,都会给吃掉
#关闭所有输出
[chengmo@centos5 shell]$ls test.sh test1.sh 1>&- 2>&-
#关闭 1 ,2 文件描述符
[chengmo@centos5 shell]$ls test.sh test1.sh 2>/dev/null 1>/dev/null
#将1,2 输出转发给/dev/null设备
[chengmo@centos5 shell]$ls test.sh test1.sh >/dev/null 2>&1
#将错误输出2 绑定给 正确输出 1,然后将 正确输出 发送给 /dev/null设备 这种常用
<p>[chengmo@centos5 shell]$ls test.sh test1.sh &>/dev/null
#& 代表标准输出 ,错误输出 将所有标准输出与错误输出 输入到/dev/null文件
|
注意:
1、shell遇到”>”操作符,会判断右边文件是否存在,如果存在就先删除,并且创建新文件。不存在直接创建。 无论左边命令执行是否成功。右边文件都会变为空。
23 命令替换
语法
`command` 使用反引号
下面的例子中,将命令执行结果保存在变量中:
#!/bin/bash DATE=`date` echo "Date is $DATE" USERS=`who | wc -l` echo "Logged in user are $USERS" UP=`date ; uptime` echo "Uptime is $UP"
24
变量替换
变量替换可以根据变量的状态(是否为空、是否定义等)来改变它的值可以使用的变量替换形式:
形式 | 说明 |
---|---|
${var} | 变量本来的值 |
${var:-word} | 如果变量 var 为空或已被删除(unset),那么返回 word,但不改变 var 的值。 |
${var:=word} | 如果变量 var 为空或已被删除(unset),那么返回 word,并将 var 的值设置为 word。 |
${var:?message} | 如果变量 var 为空或已被删除(unset),那么将消息 message 送到标准错误输出,可以用来检测变量 var 是否可以被正常赋值。 若此替换出现在Shell脚本中,那么脚本将停止运行。 |
${var:+word} | 如果变量 var 被定义,那么返回 word,但不改变 var 的值。 |
请看下面的例子:
#!/bin/bash
echo ${var:-"Variable is not set"}
echo "1 - Value of var is ${var}"
echo ${var:="Variable is not set"}
echo "2 - Value of var is ${var}"
unset var
echo ${var:+"This is default value"}
echo "3 - Value of var is $var"
var="Prefix"
echo ${var:+"This is default value"}
echo "4 - Value of var is $var"
echo ${var:?"Print this message"}
echo "5 - Value of var is ${var}"
运行结果:
Variable is not set 1 - Value of var is Variable is not set 2 - Value of var is Variable is not set 3 - Value of var is This is default value 4 - Value of var is Prefix Prefix 5 - Value of var is Prefix
25
Shell 函数返回值只能是整数,一般用来表示函数执行成功与否,0表示成功,其他值表示失败。如果 return 其他数据,比如一个字符串,往往会得到错误提示:“numeric argument required”。
如果一定要让函数返回字符串,那么可以先定义一个变量,用来接收函数的计算结果,脚本在需要的时候访问这个变量来获得函数返回值。
像删除变量一样,删除函数也可以使用 unset 命令,不过要加上 .f 选项,如下所示:
如果你希望直接从终端调用函数,可以将函数定义在主目录下的 .profile 文件,这样每次登录后,在命令提示符后面输入函数名字就可以立即调用。26 引号
单引号字符串的限制:
- 单引号里的任何字符都会原样输出,单引号字符串中的变量是无效的;
- 单引号字串中不能出现单引号(对单引号使用转义符后也不行)。
- 双引号里可以有变量
- 双引号里可以出现转义字符
像其他语言一样,Shell 也可以包含外部脚本,将外部脚本的内容合并到当前脚本。
Shell 中包含脚本可以使用:
. filename
source filename