Bash 是 Linux 和 Mac 的默认 Shell(命令行环境),可以把多个命令组合自动执行,用于自动化运维、日志分析、备份、部署等任务。
本文参考:
一、Bash 的基本语法
- bash 是由多个命令组合而成,bash中的基本命令格式如下:
$ command [ arg1 ... [ argN ]]
- 如果命令过长,可通过反斜杠(
\)换行:
$ echo foo bar
# 等同于
$ echo foo \
bar
- 分号(
;)是命令的结束符,使得一行可以放置多个命令,上一个命令执行结束后,再执行第二个命令:
$ clear; ls
# 使用分号时,第二个命令总是接着第一个命令执行,不管第一个命令执行成功或失败。
- 除了分号,Bash 还提供两个命令组合符
&&和||,允许更好地控制多个命令之间的继发关系:
Command1 && Command2 # 如果Command1命令运行成功,则继续运行Command2命令
Command1 || Command2 # 如果Command1命令运行失败,则继续运行Command2命令
二、Bash 变量
1、环境变量
环境变量是 Bash 环境自带的变量,进入 Shell 时已经定义好了,可以直接使用,env命令或printenv命令,可以显示所有环境变量。
查看单个环境变量的值,可以使用printenv命令或echo命令:
$ printenv PATH #无需添加$
# 或者
$ echo $PATH #需要添加$
2、自定义变量
用户创建变量的时候,变量名必须遵守下面的规则。
- 字母、数字和下划线字符组成。
- 第一个字符必须是一个字母或一个下划线,不能是数字。
- 不允许出现空格和标点符号。
变量声明的语法如下:
variable=value
等号左边是变量名,右边是变量。如果变量包含空格,需要将变量包含在双引号中:
myvar="hello world"
变量支持多种数据来源赋值:
a=z # 变量 a 赋值为字符串 z
b="a string" # 变量值包含空格,就必须放在引号里面
c="a string and $b" # 变量值可以引用其他变量的值
d="\t\ta string\n" # 变量值可以使用转义字符
e=$(ls -l foo.txt) # 变量值可以是命令的执行结果
f=$((5 * 7)) # 变量值可以是数学运算的结果
读取变量只需要在变量名前加$即可:
$ foo=bar
$ echo $foo
如果变量的值本身也是变量,可以使用${!varname}的语法,读取最终的值
$ myvar=USER
$ echo $myvar
USER
$ echo ${!myvar}
root
三、Bash 脚本入门
1、Shebang 行
脚本的第一行通常是指定解释器,即这个脚本必须通过什么解释器执行。这一行以#!字符开头,后面跟脚本解释器的位置,Bash 脚本的解释器一般是/bin/sh或/bin/bash。
2、脚本参数
调用脚本的时候,脚本文件名后面可以带有参数,例如:
$ script.sh word1 word2 word3
脚本文件内部,可以使用特殊变量,引用这些参数。
$0:脚本文件名,即script.sh。$1~$9:对应脚本的第一个参数到第九个参数。$#:参数的总数。$@:全部的参数,参数之间使用空格分隔。
getopts 命令
getopts命令用在脚本内部,可以解析复杂的脚本命令行参数,通常与while循环一起使用,取出脚本所有的带有前置连词线(-)的参数。
getopts optstring name
# 例如 getopts 'lha:' OPTION
- 第一个参数
optstring是字符串,给出脚本所有的连词线参数,比如,某个脚本可以有三个连词线参数-l、-h、-a,其中只有-a可以带有参数值,而-l和-h是开关参数,那么getopts的第一个参数写成lha:,带参数值的连词线参数后要加:。 - 第二个参数
name是一个变量名,用来保存当前取到的连词线参数,即l、h或a。
使用示例:
while getopts 'lha:' OPTION; do
case "$OPTION" in
l)
echo "linuxconfig"
;;
h)
echo "h stands for h"
;;
a)
avalue="$OPTARG" # 环境变量 $OPTARG 保存的就是当前连词线参数的参数值。
echo "The value provided is $OPTARG"
;;
?) # 如果用户输入了没有指定的参数(比如 -x),那么 OPTION 等于 ?
echo "script usage: $(basename $0) [-l] [-h] [-a somevalue]" >&2
exit 1
;;
esac
done
需要注意的是,只要遇到不带连词线的参数,getopts就会执行失败,从而退出while循环,比如,getopts可以解析command -l foo,但不可以解析command foo -l。
shift 命令
shift命令可以改变脚本参数,每次执行都会移除脚本当前的第一个参数($1),使得后面的参数向前一位,即$2变成$1、$3变成$2、$4变成$3,以此类推。
shift命令可以接受一个整数作为参数,指定所要移除的参数个数,默认为1:
shift 3
在使用getopts命令时,可以使用如下方式,将连词线参数去除掉:
shift "$(($OPTIND - 1))"
变量$OPTIND在getopts开始执行前是1,然后每次执行就会加1。等到退出while循环,就意味着连词线参数全部处理完毕。这时,$OPTIND - 1就是已经处理的连词线参数个数
if 语句
if是最常用的条件判断结构,只有符合给定条件时,才会执行指定的命令。它的语法如下:
if commands; then
commands
[elif commands; then
commands...]
[else
commands]
fi
test 命令
if语句中使用test命令作为判断条件:
# 写法一
test expression
# 写法二
[ expression ]
# 写法三
[[ expression ]] # 支持正则判断
以下是三种写法的示例:
# 写法一
if test -e /tmp/foo.txt ; then
echo "Found foo.txt"
fi
# 写法二
if [ -e /tmp/foo.txt ] ; then
echo "Found foo.txt"
fi
# 写法三
if [[ -e /tmp/foo.txt ]] ; then
echo "Found foo.txt"
fi
test 命令的相关参数如下:
| 操作符 | 描述 | 示例 |
|---|---|---|
| -e | 文件是否存在 | [ -e file.txt ] |
| -f | 是普通文件 | [ -f /path/to/file ] |
| -d | 是目录 | [ -d /path/to/dir ] |
| -r | 可读 | [ -r file.txt ] |
| -w | 可写 | [ -w file.txt ] |
| -x | 可执行 | [ -x script.sh ] |
| -s | 文件大小 >0 | [ -s logfile ] |
| -L | 是符号链接 | [ -L symlink ] |
| -z STRING | 字符串为空 | [ -z "$var" ] |
| -n STRING | 字符串非空 | [ -n "$var" ] |
| STRING1 = STRING2 | 字符串相等 | [ "$var1" = "$var2" ] |
| STRING1 != STRING2 | 字符串不等 | [ "$var1" != "$var2" ] |
case 结构
expression是一个表达式,pattern是表达式的值或者一个模式,可以有多条,用来匹配多个值,每条以两个分号(;)结尾:
case expression in
pattern )
commands ;;
pattern )
commands ;;
...
esac
while 循环
while循环有一个判断条件,只要符合条件,就不断循环执行指定的语句。
while condition; do
commands
done
循环语句中也支持continue和break语句,使用逻辑和其他语言一样。
for...in 循环
for...in循环用于遍历列表的每一项
for variable in list; do
commands
done
以遍历当前文件夹下的所有png文件:
for i in *.png; do
ls -l $i
done