Shell脚本编程入门

本文详细介绍了Shell脚本编程的基础知识,包括Shell的定义、环境、两种模式,以及基本语法如注释、变量、字符串、数组、运算符、输出命令、test命令、控制语句和函数等内容,适合初学者入门学习。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Shell脚本编程入门

1. 简介

1.1. 什么是Shell

  • Shell 是一个用 C 语言编写的程序,它是用户使用 Linux 的桥梁。

  • Shell 既是一种命令语言,又是一种程序设计语言。

  • Shell 是指一种应用程序,这个应用程序提供了一个界面,用户通过这个界面访问操作系统内核的服务。

注:Ken Thompson 的 sh 是第一种 Unix Shell,Windows Explorer 是一个典型的图形界面 Shell。

1.2. 什么是Shell脚本

Shell 脚本(shell script),是一种为 shell 编写的脚本程序,一般文件后缀为.sh

业界所说的 shell 通常都是指 shell 脚本,但 shell 和 shell script 是两个不同的概念。

1.3. Shell环境

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

Shell 的解释器种类众多,常见的有:

  • sh - sh 由 Steve Bourne 开发,是 Bourne Shell 的缩写,sh 是 Unix 标准默认的 shell。

  • bash - 即 Bourne Again Shell。bash 是 Linux 标准默认的 shell。

  • fish - 智能和用户友好的命令行 shell。

  • xiki - 使 shell 控制台更友好,更强大。

  • zsh - 功能强大的 shell 与脚本语言。

此外还有 ash、csh、tcsh、ksh 等,一般情况下,人们最常用的两种 shell 是 shbash ,并且并不区分它们。所以,像#!/bin/sh可以改为#!/bin/bash,这是由于在一般的linux系统当中(如redhat),sh一般设成bash的软链,使用sh调用执行脚本相当于打开了bash的POSIX标准模式

指定脚本解释器

在 shell 脚本,#! 告诉系统其后路径所指定的程序即是解释此脚本文件的 Shell 解释器。#! 被称作 shebang(也称为 Hashbang )。所以,我们会在 shell 中经常见到诸如以下的注释:

  • 指定 sh 解释器
#!/bin/sh
  • 指定 bash 解释器
#!/bin/bash

此外,我们有时候也会看到如下的方式:

#!/usr/bin/env bash

它表示从 PATH 环境变量中获取 bash 解释器,这样做的好处是程序的路径是不确定的,有时候指定的路径并不存在,可以有效防止这种情况发生。这样写还有一个好处,操作系统的 PATH 变量有可能被配置为指向程序的另一个版本。比如,安装完新版本的 bash,我们可能将其路径添加到 PATH 中,来“隐藏”老版本。如果直接用 #!/bin/bash,那么系统会选择老版本的 bash 来执行脚本,如果用 #!/usr/bin/env bash,则会使用新版本。所以一般推荐使用这种方式来指定 shell 解释器。

1.4. Shell的两种模式

交互模式

简单来说,可以将 shell 的交互模式理解为执行命令行。看到形如下面的东西,说明 shell 处于交互模式下:

[root@localhost ~]$ 

接着,便可以输入一系列 Linux 命令,比如 ls,grep,cd,mkdir,rm 等等。

非交互模式

简单来说,可以将 shell 的非交互模式理解为执行 shell 脚本。在非交互模式下,shell 从文件或者管道中读取命令并执行。当 shell 解释器执行完文件中的最后一个命令,shell 进程终止,并回到父进程。

可以使用下面的命令让 shell 以非交互模式运行:

# 作为解释器的参数
sh /path/to/script.sh
bash /path/to/script.sh

# 作为可执行程序
./path/to/script.sh
source /path/to/script.sh

其中 script.sh 是一个包含 shell 解释器可以识别并执行的命令的普通文本文件,shbash 是 shell 解释器程序。而 source /path/to/script.sh./path/to/script.sh 是等价的,表示将 script.sh 作为可执行文件运行,此时需要给该文件添加权限:

chmod +x /path/to/script.sh #使脚本具有执行权限

并且这种方式要求在脚本文件的第一行必须指明运行该脚本的程序,比如:

#!/usr/bin/env bash
echo "Hello, world!"

2. Shell的基本语法

2.1. 注释

shell 语法中,注释是特殊的语句,会被 shell 解释器忽略。

  • 单行注释 - 以 # 开头,到行尾结束。

  • 多行注释 - 以 :<<EOF 开头,到 EOF 结束。

#--------------------------------------------
# shell 注释示例
#--------------------------------------------

# echo '这是单行注释'

########## 这是分割线 ##########

:<<EOF
echo '这是多行注释'
echo '这是多行注释'
echo '这是多行注释'
EOF

注:EOF可以被替换为其他符号,如:!,'

2.2. 变量

Shell 是一种程序设计语言,它与很多设计语言一样,都可以创建变量。bash 中没有数据类型,bash 中的变量可以保存一个数字、一个字符、一个字符串等等。同时无需提前声明变量,给变量赋值会直接创建变量。

2.2.1. 变量命名规则
  • 以英文字母、数字下划线构成,首字母不能为数字

  • 不能包含空格、标点符号等特殊符号

  • 不能使用 bash 里的关键字(可以使用help命令查看保留关键字)

2.2.2. 访问变量

访问一个已经定义好的变量的语法格式是:$var${var} 。变量名外面的花括号是可选的,加不加都行,加花括号是为了帮助解释器识别变量的边界,比如:

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

如果不给skill变量加花括号,解释器就会把$skillScript当成一个变量(其值为空),所以推荐给所有变量加上花括号,这是个好的编程习惯。

已经定义的变量的值可以被修改,如以下的写法是合法的:

your_name="tom"
echo $your_name
your_name="alibaba"
echo $your_name

注:定义变量时等号=两端不能有空格,否则会报错

2.2.3. 只读变量

使用 readonly 命令可以将变量定义为只读变量,只读变量的值不能被改变。

#!/bin/bash
name="tom"
readonly name
name="jerry" # 此行报错: name: readonly variable
2.2.4. 删除变量

使用 unset 命令可以删除变量。变量被删除后不能再次使用。unset 命令不能删除只读变量。

dword="hello"  # 声明变量
echo ${dword}  # 输出变量值
# Output: hello

unset dword    # 删除变量
echo ${dword}
# Output: (空)
2.2.5. 变量类型
  • 局部变量 - 局部变量是仅在某个脚本内部有效的变量。它们不能被其他的程序和脚本访问。

  • 环境变量 - 环境变量是对当前 shell 会话内所有的程序或脚本都可见的变量。创建它们跟创建局部变量类似,但使用的是 export 关键字,shell 脚本也可以定义环境变量。

常见的环境变量:

变量 描述
$HOME 当前用户的用户目录
$PATH 用分号分隔的目录列表,shell 会到这些目录中查找命令
$PWD 当前工作目录
$RANDOM 0 到 32767 之间的整数
$UID 数值类型,当前用户的用户 ID
$PS1 主要系统输入提示符
$PS2 次要系统输入提示符

2.3. 字符串

2.3.1. 单引号和双引号

shell 字符串可以用单引号 '',也可以用双引号 "",也可以不用引号。

  • 单引号的特点

    • 单引号里不识别变量

    • 单引号里不能出现单独的单引号(使用转义符也不行),但可成对出现,作为字符串拼接使用。

  • 双引号的特点

    • 双引号里识别变量

    • 双引号里可以出现转义字符

综上,在使用引号的时候推荐使用双引号。

反引号

此外还有一种引号叫反引号" `` ",它位于键盘上 ESC 键的下方,他的作用是:反引号括起来的字符串被shell解释为命令行,在执行时,shell首先执行该命令行,并以它的标准输出结果取代整个反引号(包括两个反引号)部分。如下:

OPDATE=`date -d '-1 day' +%Y%m%d` # 该行的作用是将反引号里的命令运行结果赋值给变量OPDATE

反引号还可以嵌套使用。但需注意,嵌套使用时内层的反引号必须用反斜杠(\)将其转义。例如:

abc=`echo The number of users is \`who| wc -l\``
echo $abc

反引号是一个较老的用法,新的用法是使用 $(),它们拥有相同的作用,但是也有一些细微的差别:

  • 反引号中:若要使用转义字符需要两个反斜杠\

  • $()中: 若要使用转义字符只需用单反斜杠\

#!/bin/bash
echo `echo \$HOSTNAME`   # 反引号使用单反斜杠,$没有被转义成普通字符,所以还是执行了命令
echo $(echo \$HOSTNAME)  # 这里使用单反斜杠,$被转义成普通字符,所以被当成普通字符串
2.3.2. 字符串拼接

单引号和双引号均可用于字符串拼接:

your_name="abc"
# 使用双引号拼接
greeting="hello, "$your_name" !"
greeting_1="hello, ${your_name} !"
echo $greeting  $greeting_1
# 使用单引号拼接
greeting_2='hello, '$your_name' !'
greeting_3='hello, ${your_name} !'
echo $greeting_2  $greeting_3

输出结果为:

hello, abc ! hello, abc !
hello, abc ! hello, ${your_name} !
2.3.3. 获取字符串长度
text="12345"
echo ${#text}
# Output:
# 5
2.3.4. 截取子字符串
text="12345"
echo ${text:2:2} # 从第3个字符开始,截取2个字符
# Output:
# 34
2.3.5. 查找子字符串
text="hello"
echo `expr index "${text}" le` # 查找字符 "l" 或 "e "在 "hello" 字符串中的起始位置(哪个字母先出现就计算哪个)。
# Output:
# 2

2.4. Shell参数传递

Shell 脚本在执行时,可以向脚本传递参数,脚本内获取参数的格式为:$n。n 代表数字,0 为执行的文件名,1 为执行脚本的第一个参数,2 为执行脚本的第二个参数,以此类推……

#!/bin/bash

echo "Shell 传递参数实例!";
echo "执行的文件名:$0";
echo "第一个参数为:$1";
echo "第二个参数为:$2";
echo "第三个参数为:$3";

为脚本设置可执行权限,并执行脚本,输出结果如下所示:

$ chmod +x test.sh 
$ ./test.sh 1 2 3
Shell 传递参数实例!
执行的文件名:./test.sh
第一个参数为:1
第二个参数为:2
第三个参数为:3

另外,还有几个特殊字符用来处理参数:

参数处理 说明
$# 传递到脚本的参数个数
$* 以一个单字符串显示所有向脚本传递的参数。
$@ 与$*相同,但是使用时加引号,并在引号中返回每个参数。
$$ 脚本运行的当前进程ID号
$? 显示最后命令的退出状态。0表示没有错误,其他任何值表明有错误。

$*$@ 的区别:

  • 相同点:都是引用所有参数。

  • 不同点:只有在双引号中体现出来。假设在脚本运行时写了三个参数 1、2、3,,则 " * " 等价于 “1 2 3”(传递了一个参数),而 “@” 等价于 “1” “2” “3”(传递了三个参数)。

#!/bin/bash

echo "-- \$* 演示 ---"
for i in "$*"; do
    echo $i
done

echo "-- \$@ 演示 ---"
for i in "$@"; do
    echo $i
done

执行脚本,输出结果如下所示:

$ chmod +x test.sh 
$ ./test.sh 1 2 3
-- $* 演示 ---
1 2 3
-- $@ 演示 ---
1
2
3

2.5. 数组

bash 只支持一维数组。数组下标从 0 开始,下标可以是整数或算术表达式,其值应大于或等于 0。

2.5.1. 创建数组

Shell 数组用括号来表示,元素用"空格"符号分割开,语法格式如下:

array_name=(value1 ... valuen)

除此之外,也可以使用下标的方式定义数组,实例如下:

# 创建数组的不同方式
nums=([2]=2 [0]=0 [1]=1)
colors=(red yellow "dark blue")
array_name[0]=value0
array_name[1]=value1
array_name[2]=value2
2.5.2. 访问数组元素
  • 访问数组的单个元素:
echo ${nums[1]}
  • 访问数组的所有元素:
echo ${colors[*]}
echo ${colors[@]}
  • 访问数组的部分元素:
echo ${nums[@]:0:2} # :0:2取出了数组中从 0 开始,长度为 2 的元素。
2.5.3. 获取数组长度
echo ${#nums[*]}
2.5.4. 向数组中添加元素
colors=(white "${colors[@]}" green black)
2.5.5. 从数组中删除元素
unset nums[0] # 删除第一个元素

2.6. 运算符

2.6.1. 算术运算符

下表列出了常用的算术运算符,假定变量 x 为 10,变量 y 为 20:

运算符 说明 举例
+ 加法 expr $x + $y 结果为 30。
- 减法 expr $x - $y 结果为 -10。
* 乘法 expr $x \* $y 结果为 200(乘号使用时需要加转义符)。
/ 除法 expr $y / $x 结果为 2。
% 取余 expr $y % $x 结果为 0。
= 赋值 x=$y 将把变量 y 的值赋给 x。
== 相等。用于比较两个数字,相同则返回 true。 [ $x == $y ] 返回 false。
!= 不相等。用于比较两个数字,不相同则返回 true。 [ $x != $y ] 返回 true。

注:条件表达式要放在方括号之间,并且要有空格,例如: [$x==$y] 是错误的,必须写成 [ $x == $y ]

#!/usr/bin/env bash

x=10
y=20

echo "x=${x}, y=${y}"

val=`expr ${
    x} + ${
    y}`
echo "${x} + ${y} = $val"

val
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值