最近在服务器和自己的电脑上都有用docker快速部署环境的需求,特别是当涉及到数据卷映射时,命令比较长,所以考虑到写sh脚本来自动完成,正好之前一直想学bash脚本的编写,趁机总结一下
目录
Shebang 行
脚本的第一行通常是指定解释器,即这个脚本必须通过什么解释器执行。这一行以#!
字符开头,这个字符称为 Shebang,所以这一行就叫做 Shebang 行。
sh脚本的解释器一般都是bash,所以首行一般写为
#!/bin/bash
或
#!/usr/bin/env bash
如果 Bash 解释器不放在目录/bin
,脚本就无法执行了。为了保险,可以写成下面用env的命令的(这个命令总是在/usr/bin
目录),返回 Bash 可执行文件的位置
Shebang 行不是必需的,但是建议加上这行。如果缺少该行,就需要手动将脚本传给解释器
# 带Shebang 行时执行方式:
./script.sh
# 不带Shebang行时执行方式:
bash ./script.sh
由于在执行sh脚本时需要指定脚本的路径,如果有比较多的sh脚本的话,建议执行如下操作:
- 先在主目录新建一个
~/bin
子目录,专门存放可执行脚本,然后把~/bin
加入$PATH
export PATH=$PATH:~/bin
# 上面命令改变环境变量$PATH,将~/bin添加到$PATH的末尾。可以将这一行加到~/.bashrc文件里面,然后重新加载一次.bashrc,这个配置就可以生效了。
2. 执行
source ~/.bashrc
以后不管在什么目录,直接输入脚本文件名,脚本就会执行,例如: script.sh
注释
Bash 脚本中,#
表示注释,可以放在行首,也可以放在行尾。
# 本行是注释
echo 'Hello World!'
echo 'Hello World!' # 井号后面的部分也是注释
脚本参数
调用脚本的时候,脚本文件名后面可以带有参数,例如:
$ script.sh word1 word2 word3
脚本文件内部,可以使用特殊变量,引用这些参数。
$0
:脚本文件名,即script.sh
。$1
~$9
:对应脚本的第一个参数到第九个参数。$#
:参数的总数。$@
:全部的参数,参数之间使用空格分隔。$*
:全部的参数,参数之间使用变量$IFS
值的第一个字符分隔,默认为空格,但是可以自定义。
如果脚本的参数多于9个,那么第10个参数可以用${10}
的形式引用,以此类推。
调用时如果多个参数放在双引号里面,视为一个参数
变量
定义变量
定义变量时,变量名不加美元符号($),如:
your_name="qinjx"
注意,变量名和等号之间不能有空格,这可能和你熟悉的所有编程语言都不一样。
除了显式地直接赋值,还可以用语句给变量赋值,如:
for file in `ls /etc`
使用变量
使用一个定义过的变量,只要在变量名前面加美元符号即可,如:
your_name="qinjx"
echo $your_name
echo ${your_name}
变量名外面的花括号是可选的,加不加都行,加花括号是为了帮助解释器识别变量的边界,比如下面这种情况:
for skill in Ada Coffe Action Java; do
echo "I am good at ${skill}Script"
done
如果不给skill变量加花括号,写成echo "I am good at $skillScript",解释器就会把$skillScript当成一个变量(其值为空),代码执行结果就不是我们期望的样子了。
推荐给所有变量加上花括号,这是个好的编程习惯
引号
单引号
str='this is a string'
单引号字符串的限制:
- 单引号里的任何字符都会原样输出,单引号字符串中的变量是无效的
- 单引号字串中不能出现单引号(对单引号使用转义符后也不行)
双引号
your_name='qinjx'
str="Hello, I know your are \"$your_name\"! \n"
- 双引号里可以有变量
- 双引号里可以出现转义字符
字符操作
拼接字符串:
your_name="qinjx"
greeting="hello, "$your_name" !"
greeting_1="hello, ${your_name} !"
echo $greeting $greeting_1
获取字符串长度:
string="abcd"
echo ${#string} #输出:4
提取子字符串:
string="alibaba is a great company"
echo ${string:1:4} #输出:liba
读入
通过read将用户输入读入变量中
#!/bin/sh
# Author : Zara Ali
# Copyright (c) Tutorialspoint.com
# Script follows here:
echo "What is your name?"
read PERSON
echo "Hello, $PERSON"
输出:
$./test.sh
What is your name?
Zara Ali
Hello, Zara Ali
$
条件判断
if condition1
then
command1
elif condition2
command2
else
commandN
fi
if可以直接判断命令的执行结果(每个命令执行完成后也会有一个返回值,如果命令执行成功则返回0,如果执行失败则返回1), 所以也可以用如下方式写脚本
if cd $some_directory; then
rm *
else
echo "Could not change directory! Aborting." 1>&2
exit 1
fi
当然,更简介的方式是使用逻辑运算符&&
和||
# 第一步执行成功,才会执行第二步
cd $some_directory && rm *
# 第一步执行失败,才会执行第二步
cd $some_directory || exit 1
case
case "${opt}" in
"Install-Puppet-Server" )
install_master $1
exit
;;
"Install-Puppet-Client" )
install_client $1
exit
;;
"Config-Puppet-Server" )
config_puppet_master
exit
;;
"Config-Puppet-Client" )
config_puppet_client
exit
;;
"Exit" )
exit
;;
* ) echo "Bad option, please choose again"
esac
case的语法和C family语言差别很大,它需要一个esac(就是case反过来)作为结束标记,每个case分支用右圆括号,用两个分号表示break
While循环
while condition
do
command
done
for循环
for i in ...;
do
......
done
或
for ((i=0; i<10; i++));
do
......
done
exit命令
exit用于终止当前脚本的执行,并向shell返回一个推出值
如果直接使用exit,会将最后一条命令的退出状态作为整个脚本的退出状态
exit后可以加参数,该参数就是退出状态:
# 退出值为0(成功)
$ exit 0
# 退出值为1(失败)
$ exit 1
退出时,脚本会返回一个退出值。脚本的退出值,0
表示正常,1
表示发生错误,2
表示用法不对,126
表示不是可执行脚本,127
表示命令没有发现。如果脚本被信号N
终止,则退出值为128 + N
。简单来说,只要退出值非0,就认为执行出错。
推荐
- Advanced Bash-Scripting Guide,非常详细,非常易读,大量example,既可以当入门教材,也可以当做工具书查阅
- 脚本编程30分钟入门
文章评论