变量
与TCL类似,在变量前加$来取值
环境变量
#!/bin/bash
# display user information from the system.
echo "User info for userid: $USER"
echo UID: $UID
echo HOME: $HOME
用户变量
使用等号给用户变量赋值,在变量、等号和值之间不能出现空格
var1=10
var2=-57
var3=testing
var4="still more testing"
命令替换
- 反引号字符`
- $()格式
testing=`date`
testing=$(date)
#!/bin/bash
testing=$(date)
echo "The date and time are : " $testing
显示消息
echo命令可用单引号或者双引号来划定文本字符串。当字符串内本身自带单引号时,外部只能用双引号,反之亦然
echo "This is a test to see if you're paying attention"
echo 'Rich says "scripting is easy"'
重定向输入和输出
输出重定向
格式: command > outputfile
功能: 将命令的输出发送到一个文件中。如果不想覆盖原有的文件内容,则使用双大于号(>>)来追加数据
输入重定向
格式: command < inputfile
功能: 将文件的内容重定向到命令
双小于号(<<)则表示内联输入重定向,此时只需要输入用于指定重定向的数据就好了,但数据的开始和结尾必须使用一个文本标记来划分(可以是任何字符串),且数据的开始和结尾的文本标记必须一致,例如:
$ wc << EOF
> string 1
> string 2
> string 3
> EOF
管道
格式: command1 | command2
功能: 将一个命令的输出重定向到另一个命令中,Linux系统会同时执行这两个命令,在系统内部把它们连接起来。在第一个命令产生输出的同时,输出会立即被送给第二个命令
rpm -qa | sort | more
数学运算
expr命令
expr 1 + 5
# 某些字符需要转义
expr 3 \* 4
使用方括号
此时不存在转义问题
var1=$[1 * 3]
使用bc
由于bash shell的数学运算符只支持整数,进行数学计算需考虑用z shell或者内建bash计算器bc
格式: var=$(echo "options; expression" | bc)
#!/bin/bash
var1=$(echo "scale=4; 3.44 / 5" | bc)
echo The answer is $var1
退出脚本
shell中运行的每一个命令都使用状态退出码(0~255之间的整数值)来告诉shell它已经运行完毕,一个成功结束的命令的退出状态码是0.默认情况下,shell脚本会以脚本中最后一个命令的退出状态码退出,可以使用exit n对退出状态码进行自定义
结构化命令
if-then
格式:
if command
then
commands
fi
与其他语言不同,bash shell的if语句会运行if后面的那个命令。如果该命令的退出状态码为0,位于then的部分就会执行。fi用来表示if-then语句到此结束
#!/bin/bash
# testing the if statement
if pwd
then
echo "It worked"
fi
if-then-else
格式:
if command
then
commands
else
commands
fi
嵌套if
格式:
if command
then
commands
elif command2
then
more commands
fi
test
test可用于通过if-then语句测试命令退出状态码以外的其他条件
格式:
if test condition
then
commands
fi
如果不写test命令的condition部分,则会以非零状态码退出并直接执行else部分
如果不想使用test命令,则可以换用如下的形式,注意,第一个方括号之后和第二个方括号之前必须加上一个空格,否则就会报错
if [ condition ]
then
commands
fi
数值比较
比较 | 描述 |
---|---|
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 |
if [ $value1 -gt 5 ]
then
echo "......"
else
echo "........"
fi
字符串比较
比较 | 描述 |
---|---|
str1 = str2 | str1与str2是否相同 |
str1 != str2 | str1是否与str2不同 |
str1 < str2 | 根据每个字符ASCII码数值决定排序结果 |
str1 > str2 | 同上 |
-n str1 | 检查str1的长度是否非0 |
-z str1 | 检查str1的长度是否为0 |
注意: 大于号和小于号在使用时必须转义,否则shell会把它们当作重定向符号
if [ $val1 \> $val2]
文件比较
比较 | 描述 |
---|---|
-d file | 检查file是否存在且是一个目录 |
-e file | 检查file是否存在 |
-f file | 检查file是否存在并是一个文件 |
-r file | 检查文件是否可读 |
-s file | 检查文件是否存在且非空 |
file1 -nt file2 | 检查file1是否比file2新 |
if-then的高级特性
使用双括号(( ))
双括号可以使用更多的数学赋值或比较表达式,且表达式中的大于号不需要转义
符号 | 描述 |
---|---|
val++ | 后增 |
++val | 先增 |
! | 逻辑求反 |
~ | 按位求反 |
** | 幂运算 |
& | 按位与 |
if (( $val1 ** 2 > 90 ))
使用双方括号[[ ]]
双方括号可以对字符串进行正则匹配
if [[ $USER == r* ]]
case
格式:
case variable in
pattern1 | pattern2) commands1;;
pattern3) commands2;;
*) default commands;;
esac
例:
echo '输入 1 到 4 之间的数字:'
echo '你输入的数字为:'
read aNum
case $aNum in
1) echo '你选择了 1';;
2) echo '你选择了 2';;
3) echo '你选择了 3';;
4) echo '你选择了 4';;
*) echo '你没有输入 1 到 4 之间的数字';;
esac
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
for file in /home/rich/test/*
do
if [ -d "$file" ]
then
echo "$file is a directory"
elif [ -f "$file" ]
then
echo "$file is a file"
fi
done
C语言风格的for命令
格式:
for (( i = 0; i <= 10; i++ ))
do
echo "The next number is $i"
done
使用多个变量
for (( a=1, b=0; a <= 10; a++, b-- ))
do
echo "$a - $b"
done
while
格式:
while test command
do
other commands
done
例:
while [ $var1 -gt 0 ]
do
echo $var1
var1=$[ $var1 = 1 ]
done
until
格式:
until test commands
do
other commands
done
例:
var1=100
until [ $var1 -eq 0 ]
do
echo $var1
var1=$[ $var1 - 25 ]
done
控制循环
break
跳出循环
#!/bin/bash
while :
do
echo -n "输入 1 到 5 之间的数字:"
read aNum
case $aNum in
1|2|3|4|5) echo "你输入的数字为 $aNum!" ;;
*) echo "你输入的数字不是 1 到 5 之间的! 游戏结束"
break;;
esac
done
跳出外部循环
格式:
break n
其中n指定了要跳出的循环层级。默认情况下,n为1,表明跳出的是当前的循环。如果将n设为2,break命令就会停止下一级的外部循环。
#!/bin/bash
for (( a = 1; a < 4; a++ ))
do
echo "Outer loop: $a"
for (( b = 1; b < 100; b++ ))
do
if [ $b -gt 4 ]
then
break 2
fi
echo " Inner loop: $b"
done
done
continue
跳出本次循环
#!/bin/bash
for (( var1 = 1; var1 < 15; $var1++ ))
do
if [ $var1 -gt 5 ] && [ $var1 -lt 10 ]
then
continue
fi
echo "Iteration number: $var1"
done
处理用户输入
bash shell会将一些称为位置参数的特殊变量分配给输入到命令行中的所有参数。这也包括shell所执行的脚本名称。位置参数变量是标准的数字: $0是程序名,$1是第一个参数,$2是第二个参数,依次类推,直到第九个参数$9。在第九个变量之后,必须在数字的周围加上花括号,比如${10}
#!/bin/bash
factorial=1
for (( number = 1; number <= $1 ; number++ ))
do
factorial=$[ $factorial * $number ]
done
echo The factorial of $1 is $factorial
$
$ ./test1.sh 5
The factorial of 5 is 120
参数统计
特殊变量$#含有脚本运行所携带的参数的个数
echo There were $# parameters supplied
抓取所有数据
$*: 引用所有参数,但当作一个整体
$@: 引用所有参数,但当作多个独立个体
#!/bin/bash
echo "-- \$* 演示 ---"
for i in "$*"; do
echo $i
done
echo "-- \$@ 演示 ---"
for i in "$@"; do
echo $i
done
结果如下
$ chmod +x test.sh
$ ./test.sh 1 2 3
-- $* 演示 ---
1 2 3
-- $@ 演示 ---
1
2
3
移动变量
shift命令会根据命令行参数的相对位置移动命令行参数,默认情况下会将每个参数变量向左移动一个位置。$3移到$2,$2移到$1,$1的值则会被删除
#!/bin/bash
echo
count=1
while [ -n "$1"]
do
echo "Parameter #$count = $1"
count=$[ $count + 1 ]
shift
done
获得用户输入
直接读取
read命令从标准输入(键盘)或另一个文件描述符中接受输入。在收到输入后,read命令会将数据放进一个变量
read -p "Please enter your age: " age
days=$[ $age * 365 ]
echo "That makes you over $days old! "
如果在read命令行中不指定变量,read命令则会将它收到的任何数据都放在特殊环境变量REPLY中
read -p "Enter your name: "
echo
echo Hello $REPLY, welcome to my program.
-t选项可以指定一个计时器,当计时器过期以后,read命令会返回一个非零的退出状态码
if read -t 5 -p "Please enter your name: " name
then
echo "Hello $name, welcome to my script"
else
echo
echo "Sorry, too slow! "
fi
-s选项可以使输入的数据不显示在屏幕上,但会赋给变量
从文件中读取
每次调用read命令,它都会从文件中读取一行文本。当文件中再没有内容时read命令会退出并返回非零退出状态码
#!/bin/bash
# reading data from a file
count=1
cat test | while read line
do
echo "Line $count: $line"
count=$[ $count + 1 ]
done
echo "Finished processing the file"
重定向的高级用法
标准文件描述符
- STDIN: 文件描述符代表shell的标准输入,对应的文件描述符是0。对于终端界面来说,标准输入是键盘
- STDOUT: 代表shell的标准输出,对应的文件描述符是1。对于终端界面而言,标准输出就是终端显示器
- STDERR: 代表shell的标准错误输出,对应的文件描述符是2,默认情况下错误信息也会输出到显示器输出中 重定向错误
ls -al badfile 2> test4
重定向错误和数据
ls -al test test2 test3 badtest 2> test6 1> test7
在重定向到文件描述符时,必须在文件描述符数字之前加一个&
echo "This is an error message" >&2
永久重定向
使用exec命令告诉shell在脚本执行期间重定向某个特定文件描述符
exec 1>testout
exec 0< testfile
# 这个命令会告诉shell,需要获得输入的时候,就应该从testfile读取,而不是STDIN
利用永久重定向读取文件
#!/bin/bash
# reading file input
exec 0< testfile
count=1
while read line
do
echo "Line #$count: $line"
count=$[ $count + 1 ]
done
创建自己的重定向
可以自定义3~8的文件描述符
exec 3>test13out
echo "......." >&3
在脚本中临时重定向,然后恢复默认输出设置
#!/bin/bash
# storing STDOUT, then coming back to it
exec 3>&1
exec 1>test14out
echo "This should store in the output file"
echo "along with this line."
exec 1>&3
echo "Now things should be back to normal"
手动关闭文件描述符
exec 3>&-
函数
格式
function name {
commands
}
# 或者
name() {
commands
}
要在脚本中使用函数,只需要像其他shell命令一样,在行中指定函数名就好了
#!/bin/bash
function func1 {
echo "This is an example of a function"
}
count=1
while [ $count -le 5 ]
do
func1
count=$[ $count + 1 ]
done
echo "This is the end of the loop"
func1
echo "Now this is the end of the script"
注意: 函数必须在引用前定义,即函数块必须写在调用处之前
返回值
使用return命令
bash shell使用return命令来退出函数并返回特定的退出状态码。return命令允许指定一个整数(0~255)来定义函数的退出状态码
#!/bin/bash
function db1 {
read -p "Enter a value: " value
echo "doubling the value"
return $[ $value * 2 ]
}
db1
echo "The new value is $?"
使用函数输出
通过将函数的输出保存在变量中,可以直接获得函数的输出,而不是查看退出状态码
#!/bin/bash
function db1 {
read -p "Enter a value: " value
echo $[ $value * 2 ]
}
result=$(db1)
echo "The new value is $result"
向函数传递参数
bash shell会将函数当作小型脚本来对待,这意味着可以像普通脚本那样向函数传递参数
#!/bin/bash
function func7 {
echo $[ $1 * $2 ]
}
if [ $# -eq 2 ]
then
value=$(func7 $1 $2)
#函数的$1和$2变量与脚本主体中的$1和$2变量并不相同,要在函数中使用这些值,必须在调用函数时手动传参
echo "The result is $value"
else
echo "Usage: badtest1 a b"
fi
$
$ ./test7
Usage: badtest1 a b
$ ./test7 10 15
The result is 150
全局变量与局部变量
- 全局变量: 默认情况下,脚本中定义的任何变量都是全局变量,在函数外定义的变量可以在函数内正常访问
- 局部变量: 在函数内的变量可以通过加上local关键字声明成局部变量,比如local temp=1
Comments | NOTHING