Shell 脚本

Shell 是一个命令行解释器,它为用户提供了一个向 Linux 内核发送请求以便运行程序的界面系统级程序,其主要目的是读取命令和运行其他程序。

最流行的 shell 是 Bash(Bourne Again SHell — 之所以这么称呼,是因为它源自 Stephen Bourne 编写的 shell)。 Bash 是大多数现代 Linux 实现和大多数提供 适用于 Windows 的类 Linux 工具。

1
2
3
4
5
6
7
8
#!/bin/sh
cd ~
mkdir shell_tut
cd shell_tut

for ((i=0; i<10; i++)); do
touch test_$i.txt
done
  • 第 1 行:指定脚本解释器,这里用/bin/sh 做解释器
  • 第 2 行:切换到当前用户的 home 目录
  • 第 3 行:创建一个目录 shell_tut
  • 第 4 行:切换到 shell_tut 目录
  • 第 5 行:循环条件,一共循环 10 次
  • 第 6 行:创建一个 test_0…9.txt 文件
  • 第 7 行:循环体结束

mkdir, touch 都是系统自带的程序,一般在/bin 或者/usr/bin 目录下。for, do, done 是 sh 脚本语言的关键字。

shell 和 shell 脚本的概念:

shell 是指一种应用程序,这个应用程序提供了一个界面,用户通过这个界面访问操作系统内核的服务。Ken Thompson 的 sh 是第一种 Unix Shell,Windows Explorer 是一个典型的图形界面 Shell。

shell 脚本(shell script) 是一种为 shell 编写的脚本程序。业界所说的 shell 通常都是指 shell 脚本,但读者朋友要知道,shell 和 shell script 是两个不同的概念。由于习惯的原因,简洁起见,本文出现的“shell 编程”都是指 shell 脚本编程,不是指开发 shell 自身(如 Windows Explorer 扩展开发)。

shell 编程跟 java、php 编程一样,只要有一个能编写代码的文本编辑器和一个能解释执行的脚本解释器就可以了。

当前主流的操作系统都支持 shell 编程,本文档所述的 shell 编程是指 Linux 下的 shell,讲的基本都是 POSIX 标准下的功能,所以,也适用于 Unix 及 BSD(如 Mac OS)。

  • Linux,Linux 默认安装就带了 shell 解释器。
  • Mac OS,Mac OS 不仅带了 sh、bash 这两个最基础的解释器,还内置了 ksh、csh、zsh 等不常用的解释器。
  • Windows, windows 出厂时没有内置 shell 解释器,需要自行安装,为了同时能用 grep, awk, curl 等工具,最好装一个 cygwin 或者 mingw 来模拟 linux 环境。
  1. cygwin
  2. mingw

脚本解释器

  1. sh 即 Bourne shell,POSIX(Portable Operating System Interface)标准的 shell 解释器,它的二进制文件路径通常是/bin/sh,由 Bell Labs 开发。
  2. bash Bash 是 Bourne shell 的替代品,属 GNU Project,二进制文件路径通常是/bin/bash。业界通常混用 bash、sh 和 shell。

理论上讲,只要一门语言提供了解释器(而不仅是编译器),这门语言就可以胜任脚本编程,常见的解释型语言都是可以用作脚本编程的,如:Perl、Tcl、Python、PHP、Ruby。Perl 是最老牌的脚本编程语言了,Python 这些年也成了一些 linux 发行版的预置解释器。

编译型语言,只要有解释器,也可以用作脚本编程,如 C shell 是内置的(/bin/csh),Java 有第三方解释器 Jshell,Ada 有收费的解释器 AdaScript。

如何选择 shell 编程语言:

  • 如果你已经掌握了一门编程语言(如 PHP、Python、Java、JavaScript),建议你就直接使用这门语言编写脚本程序,只要学会怎么使用 shell 解释器(Jshell、AdaScript)就可以了。
  • 如果你只是想做一些备份文件、安装软件、下载数据之类的事情,学着使用 sh,bash 会是一个好主意。
  • shell 只定义了一个非常简单的编程语言,如果你的脚本程序复杂度较高,或者要操作的数据结构比较复杂,那么还是应该使用 Python、Perl 这样的脚本语言。

第一个 shell 脚本

第一步:

新建一个扩展名为 sh(sh 代表 shell)的文件,扩展名并不影响脚本执行,如果你用 php 写 shell 脚本,扩展名就用 php 好了。第一行一般是这样:

1
2
#!/bin/bash
#!/usr/bin/php

“#!”是一个约定的标记,它告诉系统这个脚本需要什么解释器来执行。

第二步:

  • 作为可执行程序
1
2
chmod +x test.sh
./test.sh

注意,一定要写成 ./test.sh,而不是 test.sh,运行其它二进制的程序也一样。直接写 test.sh,linux 系统会去 PATH 里寻找。

  • 作为解释器参数
1
2
/bin/sh test.sh
/bin/php test.php

这种方式运行的脚本,不需要在第一行指定解释器信息,写了也没用。

语法

变量

定义变量时,变量名不加美元符号($),如:

1
your_name="qinjx"

注意,变量名和等号之间不能有空格。

使用一个定义过的变量,只要在变量名前面加美元符号即可,如:

1
2
3
your_name="qinjx"
echo $your_name
echo ${your_name}

加花括号是为了帮助解释器识别变量的边界,比如下面这种情况:

1
2
3
for skill in Ada Coffe Action Java; do
echo "I am good at ${skill}Script"
done

已定义的变量,可以被重新定义,如:

1
2
3
4
5
your_name="qinjx"
echo $your_name

your_name="alibaba"
echo $your_name

第二次赋值的时候不能写$your_name=”alibaba”,使用变量的时候才加美元符。

注释

以 “**#**” 开头的行就是注释,会被解释器忽略。
sh 里没有多行注释,只能每一行加一个#号。

字符串

字符串是 shell 编程中最常用最有用的数据类型。字符串可以用单引号,也可以用双引号,也可以不用引号。

单引号

1
str='this is a string'

单引号字符串的限制:

  • 单引号里的任何字符都会原样输出,单引号字符串中的变量是无效的
  • 单引号字串中不能出现单引号(对单引号使用转义符后也不行)

双引号

1
2
your_name='qinjx'
str="Hello, I know your are \"$your_name\"! \n"
  • 双引号里可以有变量
  • 双引号里可以出现转义字符

流程控制

sh 的流程控制不可为空,如果 else 分支没有语句执行,就不要写这个 else。

if else

  • if
1
2
3
4
5
6
7
if condition
then
command1
command2
...
commandN
fi

写成一行(适用于终端命令提示符):

1
if `ps -ef | grep ssh`;  then echo hello; fi

末尾的 fi 就是 if 倒过来拼写。

  • if else
1
2
3
4
5
6
7
8
9
if condition
then
command1
command2
...
commandN
else
command
fi
  • if else-if else
1
2
3
4
5
6
7
8
if condition1
then
command1
elif condition2
command2
else
commandN
fi
  • for
1
2
3
4
5
6
7
for var in item1 item2 ... itemN
do
command1
command2
...
commandN
done
  • while
1
2
3
4
while condition
do
command
done
1
2
3
4
while :
do
command
done
1
2
3
4
while true
do
command
done
1
for (( ; ; ))
  • until
1
2
3
4
until condition
do
command
done
  • case

示例

  1. 字符串拼接

    1
    2
    3
    hello_world="world"
    hai="hello, ${hello_world} !"
    echo $hai
  2. 获取字符串长度

    1
    2
    hello="hello"
    echo ${#hello} #output: 5
  3. 提取子字符串

1
2
hello="hello"
echo ${hello:1:3} #output: ell

参考

[1] Shell 脚本编程 30 分钟入门
[2] Advanced Bash-Scripting Guide
[3] Unix Shell Programming
[4 ]Linux Shell Scripting Tutorial - A Beginner’s handbook
[5] Linux Shell