ls
top
与平时所使用的单条Linux不同,shell脚本可以看作是多条Linux命令的组合(在一个文件里面写多条Linux命令)。事实上,shell并不是简单的多条命令的堆积,而是具有编程功能,比如它可以接收参数,可以进行判断和循环,还支持编写函数。下面就是一个统计对应文件行数的shell脚本,可以通过bash test.sh file
来检查file这个文件的行数。在检查行数之前,脚本还检查了是否指定了file,指定的file是否存在,以确保下面的统计行数是可以正常执行的。
# test.sh
if [ $# -ne 1 ]; then
echo "Usage: $0 filename"
exit 0
fi
if [ ! -f $1 ]; then
echo "File \`$1\` does not exist."
exit 0
fi
line_number=$(cat $1 | wc -l)
echo File [${1}] has ${line_number} lines.
变量
变量被用来存储值,比如上面的line_number
就是用来存储行数的,在shell中,变量的形式为变量名=变量值
,比如a=1
。等号=
的左右两边都不能有空格,否则会报错。等号的作用为赋值,即将1赋给a,在shell中,变量值只有一种类型,即所有的变量值都是字符串类型。
a=1
b=2
c=apple
访问一个变量时,可以通过$变量名
/${变量名}
来进行访问
a=1
b=2
echo $a
echo ${b}
echo是一个shell中内置的函数,它可以把后面的内容打印出来
注释
shell中使用#
作为注释符号,任何#
后面的内容都是注释,注释只用作展示,而不会被运行。
a=1 # 将1赋给a
# 下面是将2赋给b
b=2
引号
在shell中引号有三种
""
''
``
""
双引号可以用来作为模板字符串来使用,可以在字符串中使用$
符号来讲对应的变量值填充到对应的位置。在使用echo
输出内容时,默认使用的就是双引号
name=Jack
message="my name is ${name}"
echo "$message"
# my name is Jack
''
单引号是静态字符串,被单引号所包裹的内容无法用作模板字符串,一半用来放置多行文本
name=Jack
message='my name is ${name}'
echo "$message"
# my name is ${name}
long_desc='This is a long description.
1. xxxxxx
2. yyyyy'
echo $long_desc
# This is a long description.
#
# 1. xxxxxx
# 2. yyyyy
反引号是可执行字符串,被他包裹的一般是命令
echo `pwd` # pwd会首先被执行
上面这三种引号中,双引号不会打印$
,单引号全都打印,反引号则是执行包含的内容。但有些时候,可能需要双引号打印$
符号,就可以使用转义符\
来进行转义
name=jack
a="\$${name}"
echo $a # $jack
b="'aaaa"
echo $b # 'aaaa
$符号
$
符号可以被用来访问变量,除此之外,它还可以用来执行命令,方法是使用$(命令)
,与反引号的功能一样
echo $(pwd)
echo `pwd`
printf
你可能已经发现,前面用到的echo
会自动进行换行,也就是说,下面的代码在运行以后,会输出两行
echo "line1"
echo "line2"
# line1
# line2
这是因为echo在每次打印的时候,都会在输出的内容上在打印一个换行符\n
.printf与echo的功能相似,但不会打印换行符\n
printf "line1"
printf "line2"
# line1line2
要想使得printf的功能与echo一样,可以手动的在每个字符串结尾加一个\n
printf "line1\n"
printf "line2\n"
运算
shell也可以进行数字运算
expr
是shell中的运算指令,支持一般的数学运算
使用方法是expr
后跟上要运算的表达式
a=1
b=2
printf 'expr $a + $b: '
echo `expr $a + $b`
printf '$(expr $a + $b): '
echo $(expr $a + $b)
判断
shell中支持if-else判断,使用方法如下
if [ 条件 ]; then
# 条件成立时执行的代码
else
# 条件不成立时执行的代码
fi
条件的写法有很多种,比如
判断数字相同
shell中对数字的判断有专门的判断符号,
ne # !=
eq # ==
gt # >
ge # >=
lt # <
le # <=
if [ 1 -eq 1 ]; then
echo "1 == 1"
else
echo "1 != 1"
fi
判断文件是否存在
只能判断文件
if [ -f ./test.sh ]; then
echo "test.sh exists"
else
echo "test.sh does not exist"
fi
判断目录是否存在
只能判断目录
if [ -d ./test ]; then
echo "test exists"
else
echo "test does not exist"
fi
判断文件/目录是否存在
-e
可以理解为-d
和-f
的结合
if [ -e ./test ]; then
echo "test exists"
else
echo "test does not exist"
fi
判断字符串是否相同
a='apple'
b='apple'
if [ $a = $b ]; then
echo "a == b"
else
echo "a != b"
fi
对判断结果取反
a=1
b=2
if [ ! $a = $b ]; then
echo "a != b"
else
echo "a == b"
fi
判断字符串是否为空
-z
是判断字符串是否为空的符号,如果字符串为空,则返回true,否则返回false
a='apple'
if [ -z $a ]; then
echo "a is empty"
else
echo "a is not empty"
fi
使用正则
shell中可以使用=~
来进行正则匹配,这里的判断条件是正则表达式,与一般的判断条件不同,正则表达式需要用两个中括号[[ 判断条件 ]]
包裹起来
if [[ "hello" =~ ^h.* ]]; then
echo "hello"
else
echo "not hello"
fi
数组
shell中支持数组,使用方法如下
数组名=(元素1 元素2 元素3)
数组使用()
包裹,元素之间使用空格进行分割
按照下表进行访问数组
shell中的小标是从1开始的
arr=(1 2 3 'apple')
echo ${arr[1]} # 1
echo ${arr[2]} # 2
echo ${arr[3]} # 3
echo ${arr[4]} # apple
访问所有元素
arr=(1 2 3)
echo ${arr[@]}
访问数组长度
arr=(1 2 3)
echo ${#arr[@]}
截取数组
arr[@]:start:count
表示从下标为start+1的元素开始,截取count个元素
arr=(1 2 3)
echo ${arr[@]:1:2}
修改数组元素
arr=(1 2 3)
arr[3]=4
echo ${arr[@]}
合并数组
arr=(1 2 3)
arr2=(4 5 6)
arr3=(${arr[@]} ${arr2[@]})
echo ${arr3[@]}
循环
shell中支持for循环,使用方法如下
for 变量 in 取值列表; do
# 循环体
done
常见的是对数据进行循环
arr=(a b c d e f)
for i in ${arr[@]}; do
echo "element: ${i}"
done
也可以直接对一组数据进行循环
for i in 1 2 3 4 5; do
echo $i
done
循环也支持使用break和continue,break表示中断跳出循环,continue表示跳过本次循环
for i in 1 2 3 4 5; do
echo $i
if [ $i -eq 3 ]; then
break
else
echo "This line will be printed"
continue
echo "This line will not be printed"
fi
done
输出
1
This line will be printed
2
This line will be printed
3
函数
shell中支持函数,使用方法如下
function 函数名() {
# 函数体
}
比如
function hello() {
echo "hello"
}
hello
函数参数
函数使用$1
、$2
、$3
等来访问参数,$0
表示函数名,$#
表示参数个数,$@
表示所有参数
function hello() {
echo "function name: $0"
echo "argument count: $#"
echo "argument list: $@"
echo "hello $1"
}
hello "Jack" 1 2 3
对应的输出结果
function name: hello
argument count: 4
argument list: Jack 1 2 3
hello Jack
退出
shell中可以使用exit
来退出当前的shell
exit 数字
数字必须是0-255中的一个数字,0表示正常运行,1-255表示出现了错误
exit 1
exit 0
unset
shell中可以使用unset
来删除变量
name=Jack
echo $name
unset name
echo $name
hashbang
在shell脚本的第一行叫做hashbang,可以使用#!
来指定当前脚本的解释器,常见的shell解析器有zsh,bash,sh等
#!/bin/bash
echo "hello"
#!/bin/zsh
echo "hello"
使用环境变量
shell中可以使用$变量名
来访问环境变量
echo $PATH
echo $HOME
echo $PATH
echo $PWD
echo $SHELL
echo $USER
设置某个环境变量
shell中可以使用export
来设置某个环境变量
export name=Jack
echo $name
永久设置环境变量
shell中可以使用~/.bashrc
来永久设置环境变量
echo $PATH
echo 'export PATH=$PATH:/usr/local/bin' >> ~/.bashrc
echo $PATH
上面这段代码的作用是将/usr/local/bin
添加到PATH环境变量中。每次打开一个shell,都会执行~/.bashrc
中的代码,这样写可以永久的将/usr/local/bin
添加到PATH环境变量中。环境变量的PATH中路径通过:
进行分割,$PATH:/usr/local/bin
来表示将/usr/local/bin
添加到PATH环境变量中。
通配符
shell中可以使用*
来进行通配符匹配
ls *.txt
# 匹配所有的txt文件
ls hello*
# 匹配所有以hello开头的文件
ls *hello*
# 匹配所有包含hello的文件
字典
shell中可以使用declare
来定义字典
declare -A dict
dict=([name]=Jack [age]=18)
echo ${dict[name]}
echo ${dict[age]}
declare -A dict
dict=([name]=Jack [age]=18)
echo ${dict[@]}
declare -A dict
dict=([name]=Jack [age]=18)
echo ${#dict[@]}
$?
shell中可以使用$?
来获取上一条命令的返回值
ls
echo $?
检查shell解释器是否支持字典
shell中可以使用declare -A
来检查shell解释器是否支持字典
declare -A dict
if [ $? -eq 0 ]; then
echo "support dict"
else
echo "not support dict"
fi
declare的作用
shell中可以使用declare
来定义变量的作用域
function hello() {
declare name=Jack
echo $name
}