运行脚本的方式:
sh hello.sh
bash hello.sh
. ./hello.sh
source hello.sh
./hello.sh(需要给用户增加执行权限)
符号 作用
# 注释
; 命令分隔符
;; 终止case选项
. 等价于source
"" 可以读取""中的部分变量
'' 阻止String中所有字符的解释
/ 路径分隔
\ 转义
` 反引号中的命令优先执行
: 空命令,变量扩展,子串替换
? 测试操作符
$ 变量替换,命令替换
#! 用于指定当前脚本的解释器
脚本示例:
#!/bin/bash
echo hello; echo there
filename=ttt.sh
if [ -e "$filename" ]; then # 注意: "if"和"then"需要分隔,-e用于判断文件是否存在
echo "File $filename exists."; cp $filename $filename.bak
else
echo "File $filename not found."; touch $filename
fi; echo "File test complete."
脚本解释:
上面脚本使用了一个if分支判断一个文件是否存在,如果文件存在打印相关信息并将该文件备份;如果不存在打印相关信息并创建一个新的文件。最后将输出"测试完成"。
-e filename 如果 filename存在,则为真
-d filename 如果 filename为目录,则为真
-f filename 如果 filename为常规文件,则为真
-L filename 如果 filename为符号链接,则为真
-r filename 如果 filename可读,则为真
-w filename 如果 filename可写,则为真
-x filename 如果 filename可执行,则为真
-s filename 如果文件长度不为0,则为真
-h filename 如果文件是软链接,则为真
-n 当串的长度大于0时为真(非空串)
-z 当串的长度为0时为真(空串)
脚本示例:
#!/bin/bash
varname=b
case "$varname" in
[a-z]) echo "abc";;
[0-9]) echo "123";;
esac
脚本解释:
上面脚本使用case语句,首先创建了一个变量初始化为b,然后使用case语句判断该变量的范围,并打印相关信息。如果你有其它编程语言的经验,这将很容易理解。
反斜线\:
\n 表示新
\r 表示回车
\t 表示水平制表符
\v 表示垂直制表符
\b 表示后退符
\a 表示"alert"(蜂鸣或者闪烁)
\0xx 转换为八进制的ASCII码, 等价于0xx
" 表示引号字面的意思
脚本示例:
$ cp `mkdir back` test.sh back
$ ls
脚本解释:
先创建了 back 目录,然后复制 test.sh 到 back 目录
#!/bin/bash
condition=5
if [ $condition -gt 0 ] #gt表示greater than,也就是大于,同样有-lt(小于),-eq(等于)
then : # 什么都不做,退出分支
else
echo "$condition"
fi
: > test.sh #把test.sh 文件清空,如果没有这个文件就创建这个文件,功能和 cat /dev/null > test.sh 相同,但是并不会产生一个新的进程
在一个双括号中, ? 就是一个三元表达式
符号 作用
() 局部变量,初始化数组
{} 文件名扩展
[] 条件测试,数组元素
| 分析前面命令的输出,并将输出作为后面命令的输入
- 选项,重定向stdin或stdout
~ home目录
命令组: ()
在括号中的变量,由于是在子shell中,所以对于脚本剩下的部分是不可用的。父进程,也就是脚本本身,将不能够读取在子进程中创建的变量,也就是在子shell 中创建的变量
脚本示例:
#!/bin/bash
a=123
( a=321; )
echo "$a" #a的值为123而不是321,因为括号将判断为局部变量
初始化数组:
arr=(1 2 3 4)
echo ${arr[2]}
命令组: {}
文件名扩展
#!/bin/bash
if [ ! -w 't.txt' ];
then
touch t.txt
fi
echo 'test test' >> t.txt
cp t.{txt,back}
代码块
#!/bin/bash
a=123
{ a=321; }
echo "a = $a"
bash xxx.sh
a=321 #a的值被修改
命令组: []
条件测试
#!/bin/bash
a=5
if [ $a -lt 10 ]
then
echo "a: $a"
else
echo 'a>10'
fi
数组元素
#!/bin/bash
arr=(12 22 32)
arr[0]=10
echo ${arr[0]}
命令组: <>
重定向
test.sh > filename:重定向test.sh的输出到文件 filename 中。如果 filename 存在的话,那么将会被覆盖。
test.sh &> filename:重定向 test.sh 的 stdout(标准输出)和 stderr(标准错误)到 filename 中。
test.sh >&2:重定向 test.sh 的 stdout 到 stderr 中。
test.sh >> filename:把 test.sh 的输出追加到文件 filename 中。如果filename 不存在的话,将会被创建
命令组: |
分析前面的输出,并将输出作为后面命令的输入
#!/bin/bash
tr 'a-z' 'A-Z'
exit 0
chmod 755 test26.sh
ls -l | ./test26.sh
输出的内容均变为了大写字母
命令组: -
选项,前缀
#!/bin/bash
a=5
b=5
if [ "$a" -eq "$b" ]
then
echo "a is equal to b."
fi
bash test27.sh
a is equal to b.
重定向stdin或stdout
变量定义
注意
变量名和等号之间不能有空格。同时,变量名的命名须遵循如下规则:
首个字符必须为字母(a-z,A-Z)。
中间不能有空格,可以使用下划线(_)。
不能使用标点符号。
不能使用bash里的关键字(可用help命令查看保留关键字)。
除了直接赋值,还可以用语句给变量赋值,如:for file in `ls /etc`
只读变量
#!/bin/bash
myUrl="http://www.shiyanlou.com"
readonly myUrl
myUrl="http://www.shiyanlou.com"
运行脚本报错
特殊变量
局部变量
环境变量
位置参数
从命令行传递到脚本的参数:$0,$1,$2,$3...
$0就是脚本文件自身的名字,$1 是第一个参数,$2 是第二个参数,$3 是第三个参数,然后是第四个。$9 之后的位置参数就必须用大括号括起来了,比如,${10},${11},${12}。
$# : 传递到脚本的参数个数
$* : 以一个单字符串显示所有向脚本传递的参数。与位置变量不同,此选项参数可超过 9个
$$ : 脚本运行的当前进程 ID号
$! : 后台运行的最后一个进程的进程 ID号
$@ : 与$*相同,但是使用时加引号,并在引号中返回每个参数
$: 显示shell使用的当前选项,与 set命令功能相同
$? : 显示最后命令的退出状态。 0表示没有错误,其他任何值表明有错误。
脚本:
#!/bin/bash
# 作为用例, 调用这个脚本至少需要10个参数, 比如:
# bash test.sh 1 2 3 4 5 6 7 8 9 10
MINPARAMS=10
echo
echo "The name of this script is \"$0\"."
echo "The name of this script is \"`basename $0`\"."
echo
if [ -n "$1" ] # 测试变量被引用.
then
echo "Parameter #1 is $1" # 需要引用才能够转义"#"
fi
if [ -n "$2" ]
then
echo "Parameter #2 is $2"
fi
if [ -n "${10}" ] # 大于$9的参数必须用{}括起来.
then
echo "Parameter #10 is ${10}"
fi
echo "-----------------------------------"
echo "All the command-line parameters are: "$*""
if [ $# -lt "$MINPARAMS" ]
then
echo
echo "This script needs at least $MINPARAMS command-line arguments!"
fi
echo
exit 0
运行结果:
$ bash test30.sh 1 2 10
The name of this script is "test.sh".
The name of this script is "test.sh".
Parameter #1 is 1
Parameter #2 is 2
-----------------------------------
All the command-line parameters are: 1 2 10
This script needs at least 10 command-line arguments!
算数运算符
原生bash不支持简单的数学运算,但是可以利用其他命令实现,如:awk/expr
注意使用反引号`
表达式与运算符之间要有空格: $a + $b可以, $a+$b不行
条件表达式放在中括号中也要有空格: [ $a == $b ]可以, [$a==$b]不行
乘号* 前面必须要有反斜线\,才能实现乘法运算
脚本:
#!/bin/bash
a=10
b=20
val=`expr $a + $b`
echo "a + b : $val"
val=`expr $a - $b`
echo "a - b : $val"
val=`expr $a \* $b`
echo "a * b : $val"
val=`expr $b / $a`
echo "b / a : $val"
val=`expr $b % $a`
echo "b % a : $val"
if [ $a == $b ]
then
echo "a == b"
fi
if [ $a != $b ]
then
echo "a != b"
fi
关系运算符只支持数字,不支持字符串,除非字符串的值是数字
-eq 检测两个数是否相等,相等返回true
-ne 检测两个数是否相等,不相等返回true
-gt 检测左边的数是否大于右边的,是,返回true
-lt 检测左边的数是否小于右边的,是,返回true
-ge 检测左边的数是否大于等于右边的,是,返回true
-le 检测左边的数是否小于等于右边的,是,返回true
脚本:
#!/bin/bash
a=10
b=20
if [ $a -eq $b ]
then
echo "$a -eq $b : a == b"
else
echo "$a -eq $b: a != b"
fi
逻辑运算符
&& 逻辑的AND
|| 逻辑的OR
脚本:
#!/bin/bash
a=10
b=20
if [[ $a -lt 100 && $b -gt 100 ]]
then
echo "return true"
else
echo "return false"
fi
if [[ $a -lt 100 || $b -gt 100 ]]
then
echo "return true"
else
echo "return false"
fi
字符串运算符
= 检测两个字符串是否相等,相等返回true
!= 检测两个字符串是否相等,不相等返回true
-z 检测字符串长度是否为0,为0 返回true
-n 检测字符串长度是否为0,不为0返回true
str 检测字符串是否为空,不为空返回true
脚本:
#!/bin/bash
a="abc"
b="efg"
if [ $a = $b ]
then
echo "$a = $b : a == b"
else
echo "$a = $b: a != b"
fi
if [ -n $a ]
then
echo "-n $a : The string length is not 0"
else
echo "-n $a : The string length is 0"
fi
if [ $a ]
then
echo "$a : The string is not empty"
else
echo "$a : The string is empty"
fi
文件测试运算符
-e 文件存在
-a 文件存在(已弃用)
-f 表示这个文件是一个一般文件,不是目录或设备文件
-s 文件大小不为零
-d 表示这是一个目录
-b 表示这是一个块设备(软盘,光驱,等)
-c 表示这是一个字符设备(键盘,modem,声卡,等)
-p 表示这是一个管道
-h 这是一个符号链接
-L 这是一个符号链接
-S 这是一个socket
-t 文件被关联到一个终端设备上,一般被用来检测脚本中的stdin([-t 0])或者stdout([-t 1])是否来自一个终端
-r 文件是否具有可读权限(指的是正在运行这个测试命令的用户是否具有可读权限)
-w 文件是否具有可写权限(指的是正在运行这个测试命令的用户是否具有可写权限)
-x 文件是否具有可执行权限(指的是正在运行这个测试命令的用户是否具有可执行权限)
-g set-group-id(sgid)标记被设置的文件或目录上
-k 设置粘贴位
-O 判断是否是文件的拥有者
-G 文件的group-id 是否与你的相同
-N 从文件上一次被读取到现在为止,文件是否被修改过
f1 -nt f2 文件f1比文件f2新
f1 -ot f2 文件f1比文件f2旧
f1 -ef f2 文件f1和文件f2是相同文件的硬链接
! 非,反转上面的所有测试结果
脚本:
#!/bin/bash
file="/home/shiyanlou/test.sh"
if [ -r $file ]
then
echo "The file is readable"
else
echo "The file is not readable"
fi
if [ -e $file ]
then
echo "File exists"
else
echo "File not exists"
fi
流程控制:
if-else 语句
if 语法格式:
if condition
then
command1
command2
...
commandN
fi
if else 语法格式
if condition
then
command1
command2
...
commandN
else
command
fi
if-elif-else 语法格式
if condition1
then
command1
elif condition2
then
command2
else
command3
fi
脚本: 判断两个变量是否相等
a=10
b=20
if [ $a == $b ]
then
echo "a == b"
elif [ $a -gt $b ]
then
echo "a > b"
elif [ $a -lt $b ]
then
echo "a < b"
else
echo "Ineligible"
fi
输出: a<b
if else 语句经常与test 结合使用
脚本:
num1=$[2*3]
num2=$[1+5]
if test $[num1] -eq $[num2]
then
echo "Two numbers are equal!"
else
echo "The two numbers are not equal!"
fi
输出: Two numbers are equal!
for循环:
for var in item1 item2 .. itemN
do
command1
command2
...
commandN
done
脚本:
for loop in 1 2 3 4 5
do
echo "The value is: $loop"
done
输出:
The value is: 1
The value is: 2
The value is: 3
The value is: 4
The value is: 5
脚本:
for str in This is a string
do
echo $str
done
输出:
This
is
a
string
while 语句:不断执行一系列命令,也用于输入文件中读取数据;命令通产为测试条件
while condition
do
command
done
脚本:
#!/bin/bash
int=1
while(( $int<=5 ))
do
echo $int
let "int++"
done
使用了 Bash let 命令,它用于执行一个或多个表达式,变量计算中不需要加上 $ 来表示变量
输出:
1
2
3
4
5
while循环可用于读取键盘信息。下面的例子中,输入信息被设置为变量MAN,按结束循环。
echo 'press <CTRL-D> exit'
echo -n 'Who do you think is the most handsome: '
while read MAN
do
echo "Yes!$MAN is really handsome"
done
无限循环:
while :
do
command
done
或
while true
do
command
done
或
for(( ; ; ))
until循环
循环执行一系列命令直至条件为真时停止,一般while优于until循环,测试发生在循环末尾,至少执行一次
语法:
until condition
do
command
done
case语句:
case 值 in