1. 入参和默认变量
/root/sh-utils/test.sh para1 para2 para3
$0 $1 $2 $3
脚本名 第一个参数 第三个参数
$0
:执行的脚本名$1
:第一个参数$2
:第二个参数$#
:脚本后面传入的参数个数$@
:所有参数,并且可以被遍历$*
:所有参数,不加引号时与$@
相同,具体区别请移步 参考文章$?
:上一条命令的退出状态两个$
:当前脚本的进程 ID
2. 变量
使用=
给变量赋值:
para1="hello world" # 字符串直接赋给变量 para1
注意:
=
两边不能有空格,等号右边有空格的字符串也必须用引号括起来
使用unset
取消变量:
unset para1
使用变量时,需要在变量前添加$
,或者变量名两边添加{}
:
#!/bin/bash
para1="hello world"
echo "para1 is $para1"
echo "para1 is ${para1}!"
------
para1 is hello world
para1 is hello world!
3. 命令执行
#!/bin/bash
# save command output into var
hostname=`hostname`
echo $hostname
# call command in string
echo "Current path is $(pwd)"
# use double (()) to calculate an expression
echo "36+52=$((36+52))"
# command as a string
kernel="uname -r"
echo "kernel is $($kernel)"
# several commands as a string
cmd="ls;pwd"
echo "$(eval $cmd)"
------
centos-2
Current path is /root/GithubProjects/sh-utils
36+52=88
kernel is 3.10.0-862.14.4.el7.x86_64
24-bit-color.sh
docker-k8s-images.sh
export-http-proxy.sh
get-wechat-cover.sh
ssr.sh
start-goland.sh
test.sh
tmux-tools
/root/GithubProjects/sh-utils
4. 条件分支
if 语句
一般来说,如果命令成功执行,则其返回值为0
,因此可通过下面的方式判断上一条命令的执行结果:
if [ $? -eq 0 ]
then
echo "success"
elif [ $? -eq 1 ]
then
echo "failed,code is 1"
else
echo "other code"
fi
case 语句
case
语句的使用方法如下:
name="aa"
name="aa"
case $name in
"aa")
echo "name is $name"
;;
"")
echo "name is empty"
;;
"bb")
echo "name is $name"
;;
*)
echo "other name"
;;
esac
需要注意以下几点:
[]
前面要有空格,里面是逻辑表达式if elif
后面要跟then
,之后才是要执行的语句- 如果想打印上一条命令的执行结果,最好的做法是将
$?
赋给一个变量,因为一旦执行了一条命令,$?
的值就可能会变 case
语句的每个分支最后以两个;;
结尾,最后是esac
使用多个条件
有两种写法:
if [ 10 -gt 5 -o 10 -gt 4 ];then
echo "10>5 or 10>4"
fi
# 或者
if [ 10 -gt 5 ] || [ 10 -gt 4 ];then
echo "10>5 or 10>4"
fi
-a
,同&&
,表示与-o
,同||
,表示或!
,表示非
整数判断
-eq
:两数是否相等-ne
:两数是否不等-gt
:前者是否大于后者-lt
:前者是否小于后者-ge
:前者是否大于等于后者-le
:前者是否小于等于后者
文件目录判断
-f $filename
:是否为文件-e $filename
:是否存在-d $filename
:是否为目录-s $filename
:文件存在且不为空! -s $filename
:文件是否为空
5. 循环
for in
遍历输出脚本的参数:
# 遍历输出脚本的参数
for i in $@; do
echo $i
done
还可以指定循环变量范围:
for i in {1..5}; do
echo "Welcome $i"
done
在此基础上指定循环步长:
for i in {5..15..3}; do
echo "number is $i"
done
for do
for ((i = 0 ; i < 10 ; i++)); do
echo $i
done
while do
while [ "$ans" != "yes" ]
do
read -p "please input yes to exit loop: " ans
done
until do
ans="yes"
until [ "$ans" != "yes" ]
do
read -p "please input yes to continue loop: " ans
done
6. 函数
函数定义如下:
myfunc()
{
echo "Hello! $1"
}
或者:
function myfunc()
{
echo "Hello! $1"
}
函数调用:
para1="abelsu7"
myfunc $para1
7. 返回值
通常函数的return
返回值只支持0-255
,因此想要获得其他形式的返回值,可以通过下面的方式:
function myfunc()
{
local myresult="some value"
echo $myresult
}
val=$(myfunc) # val 的值为 some value
通过return
的方式适用于判断函数的执行是否成功:
function myfunc()
{
# do something
return 0
}
if myfunc;then
echo "success"
else
echo "failed"
fi
8. 注释
#!/bin/bash
# 这是单行注释
: << !
注释 1
注释 2
注释 3
!
: '
注释 1
注释 2
注释 3
'
: << EOF
注释 1
注释 2
注释 3
EOF
: << 字符 # 数字或者字符均可
注释 1
注释 2
注释 3
字符 # 要与之前的字符相同
9. 日志保存
脚本执行后免不了要记录日志,常用的方法是重定向。
方式一,将标准输出保存到文件中,并在控制台打印标准错误:
./test.sh > log.dat
方式二,将标准输出和标准错误都保存到日志文件中:
./test.sh > log.dat 2>&1
方式三,保存日志文件的同时,也输出到控制台:
./test.sh |tee log.dat
10. 脚本执行
./test.sh # 最常见的执行方式
sh test.sh # 在子进程中执行
sh -x test.sh # 会在终端打印执行的命令,适合调试
source test.sh # 在父进程中执行
. test.sh # 不需要赋予执行权限,临时执行
11. 脚本退出码
很多时候我们需要获取脚本的执行结果,即退出状态。通常0
表示执行成功,而非0
表示执行失败。
为了获得退出码,我们需要使用exit
,例如:
#!/bin/bash
function myfun()
{
if [ $# -lt 2 ]
then
echo "para num error"
exit 1
fi
echo "ok"
exit 2
}
if [ $# -lt 1 ]
then
echo "para num error"
exit 1
fi
returnVal=`myfun aa`
echo "end shell"
exit 0
这里需要注意的是,使用:
returnVal=`myfun aa`
这样的语句来执行函数,即使函数里面有exit
,它也不会退出脚本执行,而只是会退出该函数。这是因为exit
是退出当前进程,而这种方式执行函数,相当于fork
了一个子进程,因此不会退出当前脚本。
所以无论你的函数参数是什么,最后都会打印:
./test.sh;echo $?
0