本文主要对Shell的一些基本概念和Shell脚本的格式和执行进行简单总结,另外本文所使用的Linux环境为CentOS Linux release 8.1.1911
,所使用的Shell为bash 4.4.19(1)-release
。
Shell是一个用C语言编写的程序,它是用户使用Linux的桥梁,即连接了用户和Linux内核,让用户能够更加高效、安全、低成本地使用Linux内核,这就是Shell的本质。Shell本身不是Linux内核的一部分,它只是在内核的基础上编写的一个应用程序,这个应用程序提供了一个界面,用户通过这个界面访问操作系统内核的服务。
Shell既是一种命令语言,又是一种程序设计语言。作为命令语言,它交互式地解释和执行用户输入的命令;作为程序设计语言,它定义了各种变量和参数,并提供了许多在高级语言中才具有的控制结构,包括循环和分支。
注意:Shell也是一种编程语言,它的解释器是Shell这个程序。我们平时所说的Shell,有时候是指连接用户和内核的这个程序,有时候又是指Shell编程。
通过
Ctrl + Alt + Fn(n=1,2,3,4,5...)
快捷键可以从图形界面模式进入控制台模式,按F几就切换到控制台几,一般通过Ctrl + Alt + F1或F7
快捷键可以进入图形界面。
启动了终端仿真软件包或者登录Linux虚拟控制台后就会看到Shell命令提示符。默认Bash Shell提示符是美元符号$
,这个符号表明Shell在等待用户输入。命令提示符不是命令的一部分,它只是起到一个提示作用。不同的Linux发行版采用不同格式的提示符。CentOS中默认的提示符格式如下:
[username@host ~]$
各个部分的含义如下:
[]
是提示符的分隔符号,没有特殊含义。username
表示当前登录的用户。@
是分隔符号,没有特殊含义。host
表示当前系统的主机名。~
代表用户当前所在的目录为主目录(home目录)。如果用户当前位于主目录下的bin目录中,那么这里显示的就是bin。$
是命令提示符。Linux用这个符号标识登录的用户权限等级,如果是超级用户(root用户),提示符就是#
,如果是普通用户,提示符就是$
。注意:推荐初学者不要以
root
用户的身份直接使用shell来执行任务,因为如果shell具备较高的权限,命令中出现的输入错误有可能造成更严重的破坏,所以推荐使用普通用户登录系统,然后借助sudo
这类工具来运行特权命令。使用sudo
执行命令的效果和root
一样。
有些命令不能在一行内输入完成,需要换行,这个时候就会看到第二层命令提示符。第二层命令提示符默认为>
,提示符>
用来告诉用户命令还没输入完成,请继续输入。
命令提示符的格式不是固定的,用户可以根据自己的需要修改。Shell通过PS1
和PS2
这两个环境变量来控制提示符的格式,修改PS1
和PS2
的值就能修改命令提示符的格式,其中:
PS1
控制第一层命令提示符的格式。PS2
控制第二层命令提示符的格式。先查看PS1
和PS2
的值:
通过直接修改变量的值来修改命令提示符的格式只在当前的Shell会话期间有效,再次启动Shell后将重新使用默认的命令提示符。永久修改命令提示符的格式可以在~/.bashrc
文件中修改PS1
或PS2
变量的值,然后source ~/.bashrc
重写加载配置文件。
Shell命令的基本格式如下:
command [选项] [参数]
[]
表示可选的。Linux的选项又分为短格式选项和长格式选项:
-
和一个字母表示。--
和一个单词表示。一般情况下,短格式选项是长格式选项的缩写,也就是一个短格式选项会有对应的长格式选项。有些命令不写选项和参数也能执行,有些命令在必要的时候可以附带选项和参数。参数是命令的操作对象,一般情况下,文件、目录、用户和进程等都可以作为参数被命令操作,如果可以省略参数,则一般都有默认参数。有些命令的选项后面也可以附带参数,这些参数用来补全选项,或者调整选项的功能细节。
shell命令分为以下两种:
PATH
环境变量的路径下查找是否有对应的应用程序,如果有就运行,没有就返回错误的信息给用户。我们自己用C语言或者C++编写一个应用程序并放到PATH
指定的路径下面,那么这个程序也会成为Shell命令。Shell外部命令的本质上是一个应用程序,执行外部命令也就是启动一个新的应用程序,因为要创建新的进程并加载应用程序的代码,所以外部命令的执行速度会很慢。Shell内置命令就是一个内部的函数,外部命令就是一个应用程序。内置命令后面附带的所有选项和参数最终都以参数的形式传递给了函数,外部命令后面附带的所有选项和参数最终都以参数的形式传递给了应用程序。因为C语言或者C++程序的入口函数是main
函数,所以传递给应用程序的参数最终都被main
函数接收了,从这个角度看,传递给应用程序的参数其实也是传递给了函数。所以Shell命令后面附带的选项和参数最终都以参数的形式传递给了函数。选项中的-
也被传递给了函数,用来区分该参数是否是命令的选项。
Shell也是一种脚本语言,Shell脚本是一种为Shell编写的脚本程序。Shell脚本是解释执行的,不需要编译,Shell程序从脚本中一行一行读取并执行这些命令,相当于一个用户把脚本中的命令一行一行敲到Shell提示符下执行。
注意:业界所说的Shell通常都是指Shell脚本,但Shell和Shell脚本是两个不同的概念。Shell编程一般是指Shell脚本编程,不是指开发Shell自身。
Linux上常见的Shell脚本解释器有bash、sh、csh、tcsh等。Linux通过cat /etc/shells
可以查看系统中支持的解释器。几种常见的Shell解释器如下:
在现代Linux上,sh已经被bash代替,/bin/sh
往往是指向/bin/bash
的软链接,例如本文所使用的CentOS,进入/bin
目录使用ll | grep bash
可以看出来:
CentOS默认的解释器是Bash。通过echo $SHELL
可以查看当前Linux系统默认使用的Shell解析器:
SHELL
是Linux系统中的环境变量,它指明了当前使用的Shell程序的位置,也就是使用的哪个Shell。
Shell脚本就是一个文本文件,创建Shell脚本文件就要先新建一个文件,然后将命令输入文件中,文件扩展名建议使用sh
代表Shell,但扩展名并不影响脚本执行。
Shell脚本文件的第一行必须指定要使用的Shell解释器,格式为:
#!/bin/bash
#
用作注释行,但Shell脚本的第一行是个例外,!
后面指定Shell使用的解释器。/bin/bash
是Bash的解释器命令路径,即指定使用Bash解释器。使用sh
或bash
命令执行时,第一行可以不写#!/bin/bash
,脚本文件自己作为可执行程序执行时,第一行可以不写#!/bin/bash
,默认也是使用Bash解释器(CentOS中),不过还是建议写上。
单行注释,格式为:
# 注释内容
多行注释,格式为:
:<<!
# 注释内容
# 注释内容
!
首先编写如下Shell脚本文件,命名为test.sh
:
#!/bin/bash
echo "执行方式:"
# 获取标准输入并赋值给METHOD
read METHOD
# $$变量获取当前进程的PID
echo "$METHOD, PID:$$"
第一种执行方式是将脚本作为参数传递给解释器,以下几种写法本质上一样:
# 脚本文件用相对路径
# 使用sh的绝对路径
/bin/sh test.sh
# 使用sh命令,Shell会在/bin目录找到sh
sh test.sh
# 使用bash的绝对路径
/bin/bash test.sh
# 使用bash命令,Shell会在/bin目录找到bash
bash test.sh
# 脚本文件用绝对路径
sh /root/test.sh
bash /root/test.sh
这里以bash test.sh
为例,首先输出当前进程PID,再执行脚本文件:
这种方式本质是使用Shell解释器运行脚本文件,脚本文件不需要执行权限,并且开启了一个新进程,在新进程中运行。
第二种方式是将Shell脚本作为可执行程序执行,首先给脚本文件添加可执行权限:
chmod +x ./test.sh
然后执行,用相对路径和绝对路径都可以:
# 脚本文件用相对路径
./test.sh
# 脚本文件用绝对路径
/root/test.sh
注意,脚本文件用相对路径时,一定要加
./
表示当前目录,整条命令的意思是执行当前目录下的test.sh
脚本。如果不写./
,Linux会到系统路径(由PATH
环境变量指定)下查找test.sh
,而系统路径下显然不存在这个脚本,所以会执行失败,除非将当前路径添加到系统路径中。
这里以./test.sh
为例,首先输出当前进程PID,再执行脚本文件:
这种方式的本质是Shell脚本自己作为一个程序执行,需要可执行权限,并且开启了一个新进程,在新进程中运行。
还有一种方式就是在当前进程中运行Shell脚本,使用source
命令,该命令是内置命令中的一种。以下几种写法效果一样:
# 脚本文件用相对路径
source ./test.sh
. ./test.sh
# 不写./也可以
source test.sh
. test.sh
# 脚本文件用绝对路径
source /root/test.sh
. /root/test.sh
这里以source ./test.sh
、. ./test.sh
、. test.sh
和. /root/test.sh
为例,首先输出当前进程PID,再执行脚本文件:
这种方式的本质是source
命令读取脚本文件中的代码并依次执行,不会开启一个新的进程,而是在当前进程中运行。使用source
命令可以不用给脚本文件添加可执行权限,脚本文件用相对路径时加不加./
都行。