Bash脚本语法泛述
在理解bash之前,首先需要了解的就是CLI和GUI,GUI是我们在计算机入门课程中听到的较多也是较为熟悉的简称,表示的是图形化用户接口,现代个人计算机操作系统中基本有提供GUI,例如Windows、MacOS、Ubuntu(Linux)等。CLI听到的相对较少,表示的是命令行接口,最为直观的一个理解就是我们在ubuntu中使用的Terminal。GUI和CLI都是运行在操作系统用户态的计算机管理接口,通过CLI和GUI,我们可以实现对硬盘、显示器等硬件的管理。CLI由于其上手难度高且不直观等问题,在现代操作系统中基本不在默认为用户使用,但是在编程中,CLI却是程序员的好帮手,使用得当的话,可以大幅提供个人工作效率。
Shell是Unix系统操作系统的命令行接口(CLI),是用户和操作系统交互的通道,是用户管理计算机资源的工具。Bash是Shell的一种,由GNU开发并维护,现在为Linux内核操作系统的默认CLI。
Bash作为操作系统接口,同时也是命令行脚本语言的解释器,作为解释器和系统接口的Bash,在这两个方面没有明显的界限。本文主要从脚本语言解释器,即Bash脚本语言,视角来介绍Bash。
什么是Bash脚本?
Bash脚本从表现上来说,就是一堆指令组合在一起而形成的一个整体;从作用上来说,就是相关操作的一个规则化表示。Bash脚本语言跟一般的脚本语言有着不少差别,它不仅有着变量、函数和控制结构,还有符号扩展、重定向等一些其它为了方便和计算机交互的特性。Bash脚本的执行过程如下:
- 从脚本文件、终端程序或者**-c**选项参数读取输入
- 预处理,解析出标记并执行别名扩展
- 将符号分隔成为命令
- 执行shell扩展,将标记扩展为文件名、指令和参数
- 执行重定向并去除重定向操作和相关参数
- 执行命令
- 等待相关命令的执行结束并返回其状态
上述的流程可见下图:
Bash脚本语法
Bash脚本语法就跟一般的编程语言类似,存在着变量,函数和控制结构等,但其本质还是一系列的命令集合。Bash脚本的语法,可以说是C语言的一个简单子集。
变量定义和使用
变量定义:
variable=value
变量使用:
${variable}
# 或
$variable
有效变量名规则:
- 命名只能使用英文字母,数字和下划线,首个字符不能以数字开头
- 中间不能有空格,可以使用下划线(_)
- 不能使用标点符号
- 不能使用bash里的关键字
控制结构
Bash中常用的控制结构有条件结构和循环结构。
循环结构:
- until结构
until test-command; do
consequent-commands;
done
- while结构
while test-command; do
consequent-commands;
done
- for结构
for name [ [in [words ...] ]; ] do
commands;
done
条件结构:
- if结构
if test-commands; then
consequent-commands;
[elif more-test-commands; then
more-consequents;]
[else
alternate-consequents;]
fi
- case结构
case word in [
[(] pattern [| pattern]...) command-list ;;
...
]
esac
case结构中需要注意的是,没一个条目最终必须以‘;;’、‘;&’或‘;;&’结尾。
- select结构
select name [in words ...]; do
commands;
done
select结构用于构建Bash交互操作中的菜单。
- 条件测试 条件测试在Bash中有两种结构,分别为:
(( expression ))
[[ expression ]]
对于Bash条件测试所支持的形式,详细可参考官方文档
函数定义和使用
函数定义的语法有两种形式,分别如下:
name () {
list-commands;
} [redirections]
function name[()]{
list-commands;
}[redirections]
函数的使用语法为:
function-name function-args
需要注意,参数是直接跟在函数名后面的,并不像一般编程语言那样在小括号中。
简单实例
本文通过一个简单的文件名批量修改脚本来展示上述结构的实际使用形式。内容如下:
# !/usr/bin/env bash
# -*- coding: utf-8 -*-
if [[ $#<=0 ]]; then
echo "target directory cannot be empty!"
exit 1
fi
# 去除界定符中的空格,主要处理文件名中含有空格的问题
IFS=$(echo -en "\n\b")
for i in "$@"; do
basedir=${i}
if ! [[ -d ${basedir} ]]; then
echo "${basedir} => not directory"
continue
fi
# 打印出工作目录
echo "workspace => ${basedir}"
count=0
for j in `ls ${basedir}`; do
path="${basedir}/${j}"
echo ${path}
if [[ -d ${path} ]]; then
rm -rf ${path}
continue
fi
mv ${path} ${basedir}/${count}.${j##*.}
echo $(( count++ )) >/dev/null
done
done