什么是脚本,其实脚本是有若干个命令串起来执行的命令行,如下图。命令行一行有255个字符数的限制,所以一般长些的脚本都写在文件中。
[[email protected] ~]# date;uname -a;pwd
Thu Dec 4 17:29:52 CST 2014
date命令显示Linux localhost.localdomain 2.6.32-504.el6.x86_64 #1 SMP Wed Oct 15 04:27:16 UTC 2014 x86_64 x86_64 x86_64 GNU/Linux
uname -a命令显示/root
pwd命令显示
[[email protected] ~]# cat test.sh
#!/bin/bash
Shebang这个符号通常在Unix系统的脚本中第一行开头中写到,它指明了执行这个脚本文件的解释程序A=
test
test赋值给Aecho "$A" 双引号是弱引用,显示A变量
echo ‘$A‘
单引号是强引用,所以显示的是$A[[email protected] ~]# bash test.sh bash是命令,test.sh相当于参数
test
$A
[[email protected] ~]# A=`pwd`
命令引用,把命令结果输出[[email protected] ~]# echo $A
/root
[[email protected] ~]# ./test.sh
shell能够提供一些内部命令,并且能通过PATH环境变量找到外部命令;把命令提交给内核启动为进程,由于被当成命令来执行没有执行权限,所有被拒绝-bash: ./test.sh: Permission denied
[[email protected] ~]# ll test.sh
-rw-r--r-- 1 root root 39 Dec 5 10:49 test.sh
[[email protected] ~]# chmod a+x test.sh
[[email protected] ~]# ll test.sh
-rwxr-xr-x 1 root root 39 Dec 5 10:49 test.sh
[[email protected] ~]# ./test.sh
bash读取到了第一行的shebang,就调用bashtest
$A
变量
局部变量:函数调用的整个生命周期
如:local VAR=VALUE
本地变量:整个脚本,在脚本的函数中也可调用,也可修改
declare -a:定义数组
declare -i:定义整数
declare -r:定义只读变量,不能别unset
环境变量:定义工作目录,提示字符,执行命令搜索路径等
1、全局环境变量(范围全局)
export VAR_NAME=VALUE
declare -x VAR_NAME=VALUE
env,printenv
2、局部环境变量(范围局部)
set:
位置参数变量:$0(获取程序名),$1(获取第一个参数),$2,$3,$4,....$9,${10}
特殊变量:[email protected](取得所有参数),$*(取得所有参数),$#(取得参数个数)
[email protected]和$*的区别
#!/bin/bash
count1=1
for i in "$*"; do
echo "A$count1 = $*"
count1=$[ $count1 + 1 ]
done
count2=1
for j in "[email protected]"; do
echo "B$count2 = [email protected]"
count2=$[ $count2 + 1 ]
done
[[email protected] ~]# bash test.sh 1 2
A1 = 1 2
B1 = 1 2
B2 = 1 2
4种算术运算
[[email protected] ~]# A=1
[[email protected] ~]# echo $[ $A+1 ] 1、第一种算术运算
3
[[email protected] ~]# echo $[$A+1]
3
[[email protected] ~]# echo $(($A+1)) 2、第二种算术运算
3
[[email protected] ~]# let A++ 3、自增相当于let A=$A+1
[[email protected] ~]# echo $(( $A+1 ))
3
[[email protected] ~]# echo $( expr $A+1) 4、必须在+号两边那空格
2+1
[[email protected] ~]# echo $( expr $A + 1)
3
输入输出重定向
0 STDIN 标准输入 <或<<
1 STDOUT 标准输出 >或>>
2 STDERR 标准错误 2>或2>>
[[email protected] ~]# ls /etc/fstab /1111 2> test2 1> test3 如不重定向默认是在显示器上输出
[[email protected] ~]# cat test2 将STDERR错误重定向到test2
ls: cannot access /1111: No such file or directory
[[email protected] ~]# cat test3 将STDOUT重定向到test3
/etc/fstab
[[email protected] ~]# ls /etc/fstab /1111 &> test4 把正确的和错误的都重定向到test4
[[email protected] ~]# cat test4
ls: cannot access /1111: No such file or directory
/etc/fstab
永久重定向
bash test.sh
[email protected] ~]# cat test.sh
#!/bin/bash
exec 2>testerror
exec 1>testout
echow "error"
echo "aaa"
lss /tmp
ls /tmp
[[email protected] ~]# cat testout
aaa
test
[[email protected] ~]# cat testerror
test.sh: line 5: echow: command not found
test.sh: line 7: lss: command not found
创建自己的重定向
在shell中最多可以有9个打开的文件描述符。其他6个文件描述符会从3-8,并且可以当做输入或输出重定向都行。
#!/bin/bash
exec 3>test3out
echo "11"
echo "22"
echo "33" >&3 >&重定向到 <&输入重定向
[[email protected] test]# bash test.sh
11
22
[[email protected] test]# cat test3out
33
退出状态码
当命令执行完毕会有一个退出状态码,可以通过$?查看,状态码的范围是0-255,如返回值是300,状态码会显示44(256的余数),在比较测试中命令状态码0表示true,非0为false
[[email protected] ~]# pwdd;echo $? 命令执行失败后状态码为127
-bash: pwdd: command not found
127
[[email protected] ~]# pwd;echo $? 命令执行成功,后显示为0
/root
0
- [[email protected] ~]# cat test.sh 可以通过exit来定义退出状态码
- #!/bin/bash
- exit 300
- [[email protected] ~]# echo $?
- 44
[[email protected] ~]# cat > test6 << EOF 在屏幕输出后输入到test6
> first
> second
> third
> EOF
[[email protected] ~]# cat test6
first
second
third
测试相关
测试方式有3种
1、test EXPRESSION
2、[ EXPRESSION ]
3、[[ EXPRESSION ]]
数值测试,两边需要空格
n1 -eq n2 n1是否等于n2
n1 -ge n2 n1是否大于等于n2
n1 -gt n2 n1是否大于n2
n1 -le n2 n1是否小于等于n2
n1 -lt n2 n1是否小于n2
n1 -ne n2 n1是否不等于n2
[[email protected] ~]# [ 1 -ne 0 ];echo $?
1不等于0为真0
[[email protected] ~]# [ 1 -eq 0 ];echo $?
1等于0为假1
[[email protected] ~]# [[ 10 -eq 9 ]];echo $?
10等于9为假1
[[email protected] ~]# [[ 10 -ne 9 ]];echo $?
10不等于9为真0
[[email protected] ~]# test 1 -ne 0;echo $?
1不等于0为真0
[[email protected] ~]# test 1 -eq 0;echo $?
1等于0为假1
字符测试
str1 == str2 str1是否和str2相同
str1 != str2 str1是否和str2不同
str1 < str2 str1是否比str2小
str1 > str2 str1是否比str2大
-n str1 判断str1是否不空;不空则为真,空则为假;
-z str1 判断str1是否为空;空则为真,不空则假;
[[email protected] ~]# [[ a > b ]];echo $? a大于b为假
1
[[email protected] ~]# [[ a < b ]];echo $?
a小于b为真0
[[email protected] ~]# [ a < b ];echo $? 在字符测试中单中括号是不生效的
0
[[email protected] ~]# [ a > b ];echo $?
0
- [[email protected] ~]# test a > b;echo $?
0
[[email protected] ~]# test a < b;echo $?
0
[[email protected] ~]# test a \< b;echo $?
字符比较大于等于号必须要加反斜杠转义0
[[email protected] ~]# test a \> b;echo $?
1
"$A" =~ PATTERN 如果变量A中保存的字符串能被PATTERN所匹配;即为真;否则为假
[[email protected] ~]# echo $A
blue
[[email protected] ~]# [[ "$A" =~ b ]];echo $?
0
[[email protected] ~]# [[ "$A" =~ a ]];echo $?
1
[[email protected] ~]# [[ "$A" =~ a* ]];echo $?
0
[[email protected] ~]# [[ "$A" =~ . ]];echo $?
0
[[email protected] ~]# [[ "$A" =~ * ]];echo $?
2
文件测试
-d file:目录是否存在
-e file:是否存在,存在则为真
-a $file: 同上;弃用;
-f file:是否存在且为普通文件
-h file:是否存在且为符号链接文件
-L $file:同上
-b file:是否存在且为块设备文件
-c file:是否存在且为字符设备文件
-p file:是否存在且管道文件
-S file:是否存在且为套接字文件
-s file:是否存且是否为非空文件
[[email protected] ~]# [[ -b /dev/sda ]];echo $?
0
[[email protected] ~]# [[ -b /dev/sd ]];echo $?
1
-r file:是否存在且当前用户是否拥有读权限
-w file:是否存在且当前用户是否拥有写全权限
-x file:是否存在且当前用户是否拥有执行权限
-O file:是否存在且当前用户所有
-G file:是否存用户默认组相同
[[email protected] ~]$ [[ -w /etc/passwd ]];echo $? centos用户对/etc/passwd文件不能写
1
[[email protected] ~]$ [[ -w /etc/ ]];echo $? 也可以对目录测试
1
[[email protected] ~]$ [[ -w /tmp ]];echo $?
0
[[email protected] ~]$ touch /tmp/centos
[[email protected] ~]$ ll /tmp/centos
-rw-rw-r-- 1 centos centos 0 Dec 5 14:37 /tmp/centos
[[email protected] ~]$ [[ -w /tmp/centos ]];echo $? 可以写显示为0
0
-N file:文件自从上一次被读取之后,是否被修改过
file1 -nt file2:文件file1是否比文件file2新
file1 -ot file2:文件file1是否比文件file2旧
file1 -ef file2:file1和file2是否为同一个文件的硬链接
[[email protected] ~]$ ll /etc/fstab
-rw-r--r--. 1 root root 921 Nov 28 08:29 /etc/fstab
[[email protected] ~]$ ll /tmp/test.sh
-rw-r--r-- 1 root root 339 Dec 5 10:49 /tmp/test.sh
[[email protected] ~]$ [[ /etc/fstab -nt /tmp/test.sh ]];echo $?
1
[[email protected] ~]$ [[ /etc/fstab -ot /tmp/test.sh ]];echo $? fstab比test旧
0
组合测试
或 -o:[ EXPRESSION -o EXPRESSION ]
与 -a:[ EXPRESSION -a EXPRESSION ]
非 !:[ ! EXPRESSION ]
[[email protected] ~]# [ -z "" -a -f /etc/fstab ];echo $? 2者都满足则为真
0
[[email protected] ~]# [ -n "" -a -f /etc/fstab ];echo $?
1
[[email protected] ~]# [ 1 -gt 2 ];echo $? 没加!状态码非0
1
[[email protected] ~]# [ ! 1 -gt 2 ];echo $? 加了!状态码为0
0
与:COMMAND1 && COMMAND2
或:COMMAND1 || COMMAND2
非:! COMMAND
- 在/tmp/下创建了4个文件,以下真为状态码为0
- 真 执行 && 真 执行 && 真 执行 && 真 执行
[[email protected] ~]# ls /tmp/test1 && ls /tmp/test2 && ls /tmp/test3 && ls /tmp/test4
/tmp/test1
/tmp/test2
/tmp/test3
/tmp/test4
- 真 执行 && 真 执行 || 不执行 && 真执行
[[email protected] ~]# ls /tmp/test1 && ls /tmp/test2 || ls /tmp/test3 && ls /tmp/test4
/tmp/test1
/tmp/test2
/tmp/test4
- 真 执行 || 不执行 || 不执行 && 执行
[[email protected] ~]# ls /tmp/test1 || ls /tmp/test2 || ls /tmp/test3 && ls /tmp/test4
/tmp/test1
/tmp/test4
- 假 返回错误 || 真 执行 || 不执行 && 执行
[[email protected] ~]# lss /tmp/test1 || ls /tmp/test2 || ls /tmp/test3 && ls /tmp/test4
-bash: lss: command not found
/tmp/test2
/tmp/test4
[[email protected] ~]# ls /tmp/test1 &> /dev/null;echo $? 命令执行成功状态码为0,&> /dev/null 为把错误和正常输出全部丢弃
0
[[email protected] ~]# ! ls /tmp/test1 &> /dev/null;echo $? 加了!状态码为非0
1
交互式相关
[[email protected] ~]# read -t 3 -p "Enter your menu:" menu -t为3秒后不等待输入,直接进入下一步 -p为显示输入提示,
Enter your menu:
menu为输入的参数赋值给menu
-s 选项是隐藏方式读取(如输入密码的时候)
可以和[ -z "$VAR" ] && VAR=VALUE结合使用,如3秒后为输入,赋给它默认的值
字符串操作
字符串切片${var:offset:lenth}
[[email protected] ~]# A=test;echo ${A:2:2} 取3,4两个字符
st
取字符串最后的几个字符:${var: -lenth},冒号后面有空格
[[email protected] ~]# A=test;echo ${A: -2}
st
取子串
${var#*word}:从左开始删除到第一个word字符的数据(包含word字符)
[[email protected] ~]# A=www.sina.com.cn;echo ${A#*.}
sina.com.cn
${var##*word}:从左开始删除到最后一个word之间的数据(包含word字符)
[[email protected] ~]# A=www.sina.com.cn;echo ${A##*.}
cn
${var%word*}:从右开始删除到第一次出现word的数据(包含word字符)
[[email protected] ~]# A=www.sina.com.cn;echo ${A%.*}
www.sina.com
${var%%word*}:从右开始删除到最后一次出现word的数据(包含word字符)
[[email protected] ~]# A=www.sina.com.cn;echo ${A%%.*}
www
基于模式的查找替换,删除,可使用?, *元字符
查找替换
${var/pattern/substi}:替换第一次pattern匹配到的模式
[[email protected] ~]# A="aaa bb cc aa";echo ${A/a*/AA}
AA
[[email protected] ~]# A="aaa bb cc aa";echo ${A/a?/AA}
AAa bb cc aa
${var//patten/subst}:替换所有pattern匹配到的字符
[[email protected] ~]# A="aaa bb cc aa";echo ${A//a?/AA}
AAAAbb cc AA
${var/#pattern/subst}:以行首锚定方式替换以pattern开头的行,如能匹配则替换subst
[[email protected] ~]# A="aaa bb cc aa";echo ${A/#a?/AA}
AAa bb cc aa
[[email protected] ~]# A="aaa bb cc aa";echo ${A/#b*/AA}
aaa bb cc aa
${var/%pattern/subst}:以行尾锚定方式将pattern匹配至var,如能匹配替换subst
[[email protected] ~]# A="aaa bb cc aa";echo ${A/%cc/AA}
aaa bb cc aa
[[email protected] ~]# A="aaa bb cc aa";echo ${A/%aa/AA}
aaa bb cc AA
查找并删除
${var/pattern}:删除pattern匹配到的第一次出现
[[email protected] ~]# A="aaa bb cc aa";echo ${A/b*}
aaa
[[email protected] ~]# A="aaa bb cc aa";echo ${A/b?}
aaa cc aa
${var//pattern}: 删除pattern匹配到的所有出现
[[email protected] ~]# A="aaa bb cc aa";echo ${A//a?}
bb cc
[[email protected] ~]# A="aaa bb cc aa";echo ${A//a*}
${var/#pattern}:删除以pattern开头字符
[[email protected] ~]# A="aaa bb cc aa";echo ${A/#a?}
a bb cc aa
${var/%pattern}:删除以行尾锚定pattern的字符
[[email protected] ~]# A="aaa bb cc aa";echo ${A/%a?}
aaa bb cc
字符串大小写转换
${var^^}:小写-->大写
[[email protected] ~]# A="aa";echo ${A^^}
AA
${var,,}:大写-->小写
[[email protected] ~]# A="AA";echo ${A,,}
aa
变量赋值
${var:-word}: 如果var为空或未设置,那么返回word;否则,则返回var中的值
[[email protected] ~]# echo $A
[[email protected] ~]# echo ${A:-test}
test
[[email protected] ~]# echo $A
${var:=word}:如果var为空或未设置,那么返回word,并且将word赋值给var;否则,返回var中的值
[[email protected] ~]# echo $A
[[email protected] ~]# echo ${A:=test}
test
[[email protected] ~]# echo $A
test
${var:?err_info}:如果var为空或未设置,那么返回错误信息;否则,则返回var自身的值
[[email protected] ~]# echo $A
[[email protected] ~]# echo ${A:?test}
-bash: A: test
[[email protected] ~]# echo $A
[[email protected] ~]# A=tset
[[email protected] ~]# echo ${A:?111}
tset
${var:+word}:如果var自身有正常数据,则返回word
[[email protected] ~]# echo $A
[[email protected] ~]# echo ${A:+test}
[[email protected] ~]# echo $A
[[email protected] ~]# A=AAAAA
[[email protected] ~]# echo ${A:+test}
test
[[email protected] ~]# echo $A
AAAAA