本文最后更新于 2024-07-28,文章内容可能已经过时。

什么是shell

Shell 是一个用 C 语言编写的程序,它是用户使用 Linux 的桥梁。Shell 既是一种命令语言,又是一种程序设计语言。

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

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

shell环境

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

Linux中的shell
  • Bourne Shell(/bin/sh):最早的Unix shell,由Stephen Bourne开发,也称为sh

  • C Shell(/bin/csh):由Bill Joy开发,也称为csh。它是一种基于C语言的shell,具有交互式命令行编辑和命令历史记录等特性。在许多Linux系统中,可以通过安装csh软件包来使用它。

  • Korn Shell(/bin/ksh):由David Korn开发,也称为ksh。它是Bourne Shell的扩展,提供了更多的功能和命令,如命令行编辑、作业控制、数组等。它在Solaris和AIX等Unix系统中广泛使用。

  • Bourne-Again Shell(/bin/bash):由Brian Fox和Chet Ramey开发,也称为bash。它是Bourne Shell的扩展,添加了许多新特性,如命令行编辑、自动补全、历史命令等。它是Linux系统默认的shell。

  • Z Shell(/bin/zsh):由Paul Falstad开发,也称为zsh。它是一种功能强大的shell,具有高级的命令行编辑和自动补全、路径展开等特性。它通常在Mac OS X和一些Linux系统中使用。

由于易用和免费,Bash 在日常工作中被广泛使用。同时,Bash 也是大多数Linux 系统默认的 Shell。

编写shell脚本

#!/bin/bash	
echo "Hello World !"	

#! 是一个约定的标记,它告诉系统这个脚本需要什么解释器来执行,即使用哪一种 Shell。

运行shell脚本
  • 方式一:作为可执行程序(可选绝对路径或相对路径执行)

chmod +x hello.sh
./home/ghp/hello.sh	#绝对路径

chmod +x hello.sh
./hello.sh #相对路径

备注:新建的文件默认是没有执行(x)权限的,需要赋值

  • 方式二:sh 或 bash(解释器)+ 脚本文件

# sh方式
sh hello.sh
# bash方式
bash hello.sh

使用这种方式不需要给文件设置执行权限,但是会导致shell脚本可能不是由我们指定的shell解释器执行

shell语法

shell注释
  • 行注释(Line Comments):行注释是在一行代码的末尾加上一段注释,通常使用“#”符号来表示。行注释只对当前行有效,不会影响后续代码的执行。

  • 块注释(Block Comments):块注释是在多行代码中间加上一段注释,通常使用“:<<”和“:”符号来表示。块注释可以跨越多行,但必须以“:”符号结束。

  • 文档注释(Document Comments):文档注释是用来描述代码整体的一种注释,通常放置在代码的开头。文档注释可以使用特定的标记和格式,如“/**”和“*/”符号,以方便生成文档或注释。

shell变量

  • 命名只能使用英文字母,数字和下划线_,首个字符不能以数字开头

  • 不能使用标点符号或空格

  • 不能使用 Shell 中的关键字

  • 变量名和等号之间不能有空格

自定义变量

用户定义变量是Shell脚本中自己定义的变量,可以存储任何类型的数据。

shell数据类型
  • 字符串(String)

字符串是Shell脚本中最常用的数据类型之一。字符串可以使用单引号(')或双引号(")来定义,可以包含任何字符。

  1. 单引号字符串

  1. 单引号里的任何字符都会原样输出,单引号字符串中的变量是无效的;

  2. 单引号字符串中不能出现单独一个的单引号(对单引号使用转义符后也不行),但可成对出现,作为字符串拼接使用。

  1. 双引号字符串

  • 双引号里可以有变量

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

  1. 不加引号的字符串

#!/bin/bash 
test='test'
echo '我是单引号字符串 ${test'} 
echo "我是双引号字符串 ${test}"
echo 我是没有引号字符串 ${test}


#输出
#[root@dayuan test]# bash test.sh
# 我是单引号字符串 ${test}
# 我是双引号字符串 test
# 我是没有引号字符串 test

字符串操作

  • 字符串拼接

your_name="ghp"
# 使用双引号拼接
str1="hello, "$your_name" !"
str2="hello, ${your_name} !"
echo $str1 # hello, ghp ! 
echo $str2 # hello, ghp !
# 使用单引号拼接
str3='hello, '$your_name' !'
str4='hello, ${your_name} !'
echo $str3  # hello, ghp !
echo $str4  # hello, ${your_name} !
  • 获取字符串长度

string="abcd"
echo ${#string} # 4
echo ${#string[0]} # 4
  • 获取子字符串

str="runoob is a great site"
echo ${str:6:8} # is a gr
  • 查找字符

str="runoob is a great site"
echo `expr index "$str" io` # 4

# 查找字符i或o,谁先出现就先计算谁,这里o先出现,它是第4个字符,所以输出4

  • 数字(Number)

Shell脚本中也支持数字类型,包括整数和浮点数。通常使用let命令或者$((expression))语法来计算数字。

  • 使用 declaretypeset 命令来声明整数变量。

declare -i my_integer=42

  • 数组(Array)

在 Shell 中,用括号来表示数组,数组元素用"空格"符号分割开

数组可以使用下标来访问和修改其中的元素。

array_name=(value0 value1 value2 value3)

  • 读取数组

# ${数组名[下标]}
valuen=${array_name[n]}

# @ 符号可以获取数组中的所有元素
echo ${array_name[@]}

# 获取数组的长度
# 取得数组元素的个数
length=${#array_name[@]}
# 或者
length=${#array_name[*]}
# 取得数组单个元素的长度
length=${#array_name[n]}

  • 布尔型(Boolean):Shell脚本中没有原生的布尔类型,通常使用0表示假(false),1表示真(true)。

  • 空值(Null):空值表示一个变量没有任何值。在Shell中,可以使用unset命令来清除一个变量的值。

只读变量

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

#!/bin/bash

myUrl="https://www.google.com"
readonly myUrl
myUrl="https://www.runoob.com"

使用自定义变量

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

#!/bin/bash
name='zhou'
echo my name is $name
echo my name is ${name}

# 变量名外面的花括号是可选的,加不加都行
# 加花括号是为了帮助解释器识别变量的边界

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

# 写成echo "I am good at $skillScript",解释器就会把$skillScript当成一个变量(其值为空)
删除变量

使用 unset 命令可以删除变量

#!/bin/sh

myUrl="https://www.runoob.com"
unset myUrl
echo $myUrl
位置参数变量

在执行shell脚本时可以传递参数,在脚本文件中可以使用$n来引用参数,n为一个数值代表传递的第几个参数

例如: $1 表示第一个参数,$2 表示第二个参数,依此类推

$0参数为执行的文件名

#!/bin/bash 
echo 执行的文件名为:$0
echo 第一个传参为:$1
echo 第二个传参为:$3

# 输出
# [root@dayuan test]# bash position.sh 1 2  # 参数之间空格分割
# 执行的文件名为:position.sh
# 第一个传参为:1
# 第二个传参为:2

  • 特殊字符参数

参数处理

说明

$#

传递到脚本的参数个数

$*

以一个单字符串显示所有向脚本传递的参数。
如"$*"用「"」括起来的情况、以"$1 $2 … $n"的形式输出所有参数。

$$

脚本运行的当前进程ID号

$!

后台运行的最后一个进程的ID号

$@

与$*相同,但是使用时加引号,并在引号中返回每个参数。
如"$@"用「"」括起来的情况、以"$1" "$2" … "$n" 的形式输出所有参数。

$-

显示Shell使用的当前选项,与set命令功能相同。

$?

显示最后命令的退出状态。0表示没有错误,其他任何值表明有错误。

$_

表示的是打印上一个输入参数行, 当这个命令在开头时, 打印输出文档的绝对路径名

$* $@ 区别

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

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

环境变量

由操作系统或用户设置的特殊变量,用于配置 Shell 的行为和影响其执行环境。

  • echo $PATHPATH 变量包含了操作系统搜索可执行文件的路径

  • set显示当前shell中自定义的变量,包括用户的环境变量,按变量名称排序。仅在当前Shell有效,可以显示Shell的自定义的变量

  • 直接 set 是查看当前系统中的所有环境变量,这个输出比较多,一般我们可以搭配管道符+grep命令进行筛选

  • env查看所有环境变量,也可以设置环境变量。仅在当前会话中有效,可以显示和设置用户环境变量(Linux中定义的环境变量),用法和set类似

shell运算符

原生bash不支持简单的数学运算,但是可以通过其他命令来实现,例如 awk exprexpr 最常用。

  • expr 是一款表达式计算工具,使用它能完成表达式的求值操作。

#!/bin/bash
echo $1+$2= `expr $1 + $2`

# 输出
[root@dayuan test]# bash add.sh 3 6
3+6= 9
  • 表达式和运算符之间要有空格,例如 2+2 是不对的,必须写成 2 + 2,这与我们熟悉的大多数编程语言不一样。

  • 完整的表达式要被 ` ` 包含,注意这个字符不是常用的单引号,在 Esc 键下边。

算术运算符

运算符

说明

举例

+

加法

expr $a + $b 结果为 30。

-

减法

expr $a - $b 结果为 -10。

*

乘法

expr $a \* $b 结果为 200。

/

除法

expr $b / $a 结果为 2。

%

取余

expr $b % $a 结果为 0。

=

赋值

a=$b 把变量 b 的值赋给 a。

==

相等。用于比较两个数字,相同则返回 true。

[ $a == $b ] 返回 false。

!=

不相等。用于比较两个数字,不相同则返回 true。

[ $a != $b ] 返回 true。

乘号(*)前边必须加反斜杠(\)才能实现乘法运算

关系运算符

关系运算符只支持数字,不支持字符串,除非字符串的值是数字

运算符

说明

举例

-eq

检测两个数是否相等,相等返回 true。

[ $a -eq $b ] 返回 false。

-ne

检测两个数是否不相等,不相等返回 true。

[ $a -ne $b ] 返回 true。

-gt

检测左边的数是否大于右边的,如果是,则返回 true。

[ $a -gt $b ] 返回 false。

-lt

检测左边的数是否小于右边的,如果是,则返回 true。

[ $a -lt $b ] 返回 true。

-ge

检测左边的数是否大于等于右边的,如果是,则返回 true。

[ $a -ge $b ] 返回 false。

-le

检测左边的数是否小于等于右边的,如果是,则返回 true。

[ $a -le $b ] 返回 true。

布尔运算符

运算符

说明

举例

!

非运算,表达式为 true 则返回 false,否则返回 true。

[ ! false ] 返回 true。

-o

或运算,有一个表达式为 true 则返回 true。

[ $a -lt 20 -o $b -gt 100 ] 返回 true。

-a

与运算,两个表达式都为 true 才返回 true。

[ $a -lt 20 -a $b -gt 100 ] 返回 false。

逻辑运算符

运算符

说明

举例

&&

逻辑的 AND

[[ $a -lt 100 && $b -gt 100 ]] 返回 false

||

逻辑的 OR

[[ $a -lt 100 || $b -gt 100 ]] 返回 true

字符串运算符

运算符

说明

举例

=

检测两个字符串是否相等,相等返回 true。

[ $a = $b ] 返回 false。

!=

检测两个字符串是否不相等,不相等返回 true。

[ $a != $b ] 返回 true。

-z

检测字符串长度是否为0,为0返回 true。

[ -z $a ] 返回 false。

-n

检测字符串长度是否不为 0,不为 0 返回 true。

[ -n "$a" ] 返回 true。

$

检测字符串是否不为空,不为空返回 true。

[ $a ] 返回 true。

文件测试运算符

操作符

说明

举例

-b file

检测文件是否是块设备文件,如果是,则返回 true。

[ -b $file ] 返回 false。

-c file

检测文件是否是字符设备文件,如果是,则返回 true。

[ -c $file ] 返回 false。

-d file

检测文件是否是目录,如果是,则返回 true。

[ -d $file ] 返回 false。

-f file

检测文件是否是普通文件(既不是目录,也不是设备文件),如果是,则返回 true。

[ -f $file ] 返回 true。

-g file

检测文件是否设置了 SGID 位,如果是,则返回 true。

[ -g $file ] 返回 false。

-k file

检测文件是否设置了粘着位(Sticky Bit),如果是,则返回 true。

[ -k $file ] 返回 false。

-p file

检测文件是否是有名管道,如果是,则返回 true。

[ -p $file ] 返回 false。

-u file

检测文件是否设置了 SUID 位,如果是,则返回 true。

[ -u $file ] 返回 false。

-r file

检测文件是否可读,如果是,则返回 true。

[ -r $file ] 返回 true。

-w file

检测文件是否可写,如果是,则返回 true。

[ -w $file ] 返回 true。

-x file

检测文件是否可执行,如果是,则返回 true。

[ -x $file ] 返回 true。

-s file

检测文件是否为空(文件大小是否大于0),不为空返回 true。

[ -s $file ] 返回 true。

-e file

检测文件(包括目录)是否存在,如果是,则返回 true。

[ -e $file ] 返回 true。