《初入Bash——命令调用的基本语法》源站链接,阅读体验更佳~
Bash是一门脚本语言
学好命令行是学好Linux的必经之路,那命令行到底是什么呢?
我们这里所说的命令行是Bash这样的命令行Shell,它其实是一个命令解释器,是操作系统在Shell中实现的命令行接口,用于交互式访问操作系统功能或服务。命令行界面通常在终端设备中实现,终端设备也能够使用面向屏幕的基于文本的用户界面,这些用户界面使用光标寻址将符号放置在显示屏幕上。
最本质上的,命令行Shell(以下简称cli)其实是一门脚本语言,它的上下文环境就是操作系统(当然可能需要配置Path环境变量),安装在操作系统中的可执行程序就是这门语言中一个个的函数。我们正是通过cli来调用这一个个的函数来达到和操作系统交互的目的的。
作为一门语言,cli也为我们提供了一些关键字和操作符,比如Bash中的管道符|
,重定向符>
、2>
等等,而命令在cli中则是作为一个标识符存在的,cli搜索命令的上下文就是操作系统的Path环境变量和当前目录。因为Bash是最主流的cli之一,所以这篇文章我们就以Bash为例对cli进行一个简单的介绍。
作为一门脚本语言,Bash本身具有一门高级程序设计语言的所有基本要素,比如关键字、操作符、标识符等,我们可以在Bash中声明变量,也可以直接读取当前上下文环境中已经配置好的变量;Bash也具有基本的顺序、分支、循环等控制功能。我们可以把一系列的任务编写成一个脚本文件,在需要的时候直接运行它。
不过,编写Bash脚本其实是命令行中比较高阶的内容了,这里我们先不做过多介绍,随着内容的深入,我们会逐步介绍如何编写Bash脚本。
这里,我们首先进行介绍的是如何在Bash中进行命令的调用。所谓命令,其实就是一系列已经编译成可执行文件的软件,对于Bash这门脚本语言来说,我们可以认为命令是一系列已经编写好的函数(当然,命令和我们在Bash脚本中直接用function定义的函数还是有一定区别的),我们可以在需要的时候直接调用这些函数。
当然,我们在Bash中调用命令的语法和在传统的编程语言比如C语言这样的语言中调用函数的语法在形式上存在比较大的差别,所以,这篇文章中我们重点介绍一下在Bash中调用命令的基本语法。当然,这里所谓的语法并不是强制性的,命令调用的最终形式其实是由命令本身决定的,我们这里所说的命令调用语法其实只是一种规范或者是约定,大多数命令编写这都会遵循这种规范。
命令行界面是从一种对话形式演变而来的,这种对话形式曾经是由人类通过电传打字机(TTY)进行的,在这种对话中,人类操作人员远程交换信息,通常是一次一行文本。命令行元素之间的分隔符是空白字符,行结束分隔符是换行分隔符。这是cli中广泛使用的(但不是通用的)约定。当我们在cli中输入一行文本之后,cli就负责解释我们的文本,它会分辨出我们调用的命令是什么,命令的调用是从什么地方开始,到什么地方结束,有哪些字符是需要传递给命令的信息等等。如下:
ls -l > ls_result
在上面的命令中,因为我们使用了重定向符号>
,所以Bash就会知道ls是我们想要调用的命令,而-l是需要传递给ls命令的信息,最后对ls命令调用的结果需要重定向到当前目录的ls_result文件中。
而cli提供给我们的关键字和操作符通常是比较有限的,其主要功能还是依赖于各个命令,所以命令的调用方式就显得非常重要了,所以接下来我们简单介绍一下命令调用的基本语法。
Bash中命令调用的语法
**我们上文提到,如果说Bash是一个命令解释器,是一门语言的话,那么每一个命令其实就相当于这门语言中的一个函数。**但是在Bash中调用命令的写法和我们使用C语言这样的编程语言中调用函数的写法存在比较大的差异,实际上,Bash中调用一个命令的写法基本上完全取决于命令的实现方式,不过也是有着不成文的约定的。
Linux下的约定一般是这样的command [OPTIONS]... [SOURCE]... [TARGET]
,其各个部分的说明如下:
- 一个命令中第一个输入的部分一定是命令(command)或者是可执行文件(例如Shell脚本)
- command为命令的名称,比如变换工作目录的命令cd
- 带有中括号的部分是可选的,并不一定会出现在命令中,比如cd在没有任何选项和参数的时候,默认就是把工作目录切换为当前用户的家目录
- [OPTIONS]代表的是命令的选项,下文会重点对命令的选项部分进行详细的介绍
- 其实只有[SOURCE]和[TARGET]这两组代表的是真正的参数,它们代表的就是命令要操作的资源。Bash命令的运行上下文环境是操作系统,而操作系统中的资源都是以文件的形式呈现的,所以[SOURCE]和[TARGET]一般是文件系统中的一个路径,这个路径可以是相对路径或者是绝对路径,如果是相对路径,操作系统会以当前的文件系统作为上下文来对TARGET和SOURCE进行搜索,或者是会在一些特殊的环境变量中配置的路径中进行查找,这个我们在以后的文章中会慢慢介绍。
- command、OPTIONS、SOURCE和TARGET等这几个东西之间,除了command必须位于开头之外,其他各个部分的顺序其实都不是强制规定的,可以被打乱,但是建议以上面的顺序进行书写,或者是根据命令的说明文档中的推荐格式进行书写。
- command、OPTIONS、SOURCE和TARGET等这几个东西之间以空格来区分,它们之间不论有几个空格,shell都会视为一个空格,所以空格对于Bash来说是非常重要的分割字符。
- 当我们输入完一行,按下回车键之后,命令就立即开始执行,回车键代表一行命令开始启动
- 当一个命令太长,一行无法完整输入的时候,**我们可以使用
\
来对回车键进行转义,**使命令延续到下一行,注意,\
后立即接特殊字符才能进行转义。 - 需要特别注意的是,在Linux系统中,英文大小写字母是不一样的,比如cd和CD并不一样,这和Windows系统是不一样的。
上面我们所介绍的是基本的需要注意的点,更多的内容会在后面介绍shell脚本的编写的时候再进行介绍。这篇文章中,我们只会重点介绍一下对于[OPTIONS]部分的一些说明。
OPTIONS的语法约定
上文中我们提到,Linux下的约定一般是这样的command [OPTIONS]... [SOURCE]... [TARGET]
,其中其实只有[SOURCE]和[TARGET]这两组代表的是真正的参数,而[OPTIONS]部分,则类似于其他编程语言中的具名参数,而在cli中我们通常称之为命令的选项。很多命令的选项不需要指定值,这种类型的选项类似于一个功能开关,我们只要指定了这个选项,那么就相当于打开了开关,还有一些命令选项是需要接收值的。
了解C语言的同学应该知道,C语言的入口函数main的签名是int main(int argc, char* argv[])
,它可以接收两个参数,第一个参数代表的是参数的个数,第二个才是字符串类型的参数列表,而这个列表往往就是程序接收cli信息的地方。
也就是说,整个命令行的选项只是传递给程序的一个字符串,程序可以以程序员希望的任何方式处理它,只要解释器能够告诉命令名在哪里结束,它的参数和选项在哪里开始。
这也就造成了一个问题,我们在cli中调用命令的语法并不是强制的,选项的格式在不同的cli之间可能存在很大的差别。在大多数情况下,语法是根据约定而不是操作系统的需求。
上文中我们已经介绍了调用语法的整体命令的基本约定,现在我们再对其中的[OPTIONS]部分的约定进行一个说明。
-
以
-
开头的短选项短选项使用一个
-
然后一个字母(例如-c
)来标识选项的使用。如果-
后面跟着两个或者更多的字母,这可意味着指定了多个选项或者也可能意味着一个或多个选项以及第一个需要接收值的选项以及该选项的选项值。比如:
command -p command -p -a -c -T result
而上面代码中的第二行我们一次指定了多个选项,并且为选项-T指定了选项值result,这个时候我们可以把第二行命令简写成如下的方式:
command -pac -T result # 或者是 command -pacT result # 甚至是 command -pacTresult
当我们为一个可以接收选项值的短选项指定值的时候,可以有上面的三种写法,第一种写法
command -pac -T result
中,因为-T选项是需要值的,所以我们把它单拎出来了,并且在-T和它的选项值之间加了一个空格来进行分割;写法二command -pacT result
则把所有的短选项进行了连写,但是把需要接收值的选项放到了选项列表的末尾,并在它和它的选项值之间加了空格进行分隔。第三种写法中则直接连写了,这个时候,根据约定,T选项是需要接收值的,那么选项列表中位于T之后的所有的字符将都认为是T的选项值而不是其他的选项了。 -
以
--
开头的长选项使用
--
(两个连字符)然后一个单词(例如--create
)来标识选项的使用。长选项具有更高的可读性。需要注意的是,因为长选项是有多个字符的,所以它不再支持连写,并且如果我们需要为长选项指定值,则必须在长选项和它的值之间添加分隔符进行分隔,一般是使用
=
或者是一个空格,如下:command -target=result # 使用 = 分隔选项和选项值 command -target result # 使用 空格 分隔选项和选项值
-
以
--
分隔的剩余参数如果是
--
后面不跟任何的单词而是直接跟着空白字符的话,则表示剩余的所有字符不应该被视为选项,例如:command -- -c --create
在这个示例中,
-c
和--create
都出现在--
后面,这个时候-c
和--create
就不应该被认为是选项,而是普通的参数。这是非常有用的,比如文件名本身就是以
-
开头的时候,或者是进一步的参数其实是一个内部的命令的时候,我们可以利用这一点很方便地分别对主命令和内部命令指定选项和参数。
参考自维基百科:https://en.wikipedia.org/wiki/Command-line_interface#Option_conventions_in_Unix-like_systems
查阅命令文档
通过我们上文的介绍可以看出,在Bash中进行命令调用的语法其实是比较松散的,而且每个命令都有自己的选项和参数,而可以供我们使用的命令其实是非常多的,我们不可能记住每个命令的所有细节,那么当我们刚开始接触一个命令的时候,该如何快速的对这个命令进行了解呢?
有三种方式可以查看一个命令的说明文档,首先是大多数命令都带有的–help选项,再者就是所有Unix-like操作系统中都会有的man page,还有就是Linux中提供的info工具。
其中的info page是Linux下提供的在线求助工具,其功能本质上和man page差不多,都是用来查询命令的用法或者是文件的格式,info page和man page的主要区别是内容输出格式的不同,这里我们只会重点介绍man page的使用,如果有感兴趣的同学,可以自行研究一下info page的使用。
命令的 --help 求助说明
事实上,几乎所有的Linux命令,在开发的时候,开发者都会将使用命令的语法与参数写入命令的操作过程中了。我们只要使用命令的--help
选项,就能够对该命令的用法有一个大致的了解。我们以date这个简单的命令来进行举例说明:
首先,第一行中的Usage是对date这个命令的用法的基本说明,可以看到date有两种基本的语法,一种是直接下达并且取得日期回传值,且可以 +FORAMAT 的方式来显示。至于另一种方式,则是加上 MMDDhhmmCCYY 的方式来设置日期时间。他的格式是“月月日日时时分分西元年”的格式!再往下看, 会说明主要的选项,例如 -d 的意义等等,后续又会出现 +FORMAT 的用法!从里面你可以查到我们之前曾经用过得“ date +%Y%m%d ”这个指令与选项的说明。
基本上,如果是指令,那么通过这个简单的 --help 就可以很快速的取得你所需要的选项、参数的说明了。
man page
通过命令的–help选项我们得到的只是命令的一个比较简单的说明,这里面我们并不一定能够找到自己所需要的内容,比如上面的date --help 的输出中提到了一个–date=STRING的选项,这里的STRING是什么就没有明确告诉我们;而且这个说明是会直接以标准输出的方式直接输出到我们当前的命令行窗口中的,这有可能会影响我们接下来编写命令的思路。
对于这一点,Linux提供了man page,我们只要在命令行中输入 man command 就可以查看对应命令的详细说明了,我们这里还是以date这个命令来进行简单的说明。
首先,在上面表格的第一行我们看到的是DATE(1),DATE我们知道是命令的名称,那么(1)代表的是什么呢?它代表的是“一般使用者可使用的命令”的意思。没错,这个括号里的数字是有意义的,它可以帮助我们了解或者是直接查询相关的数据。这个括号里面的数字常见的几个意义如下:
代号 | 代表内容 |
---|---|
1 | 用户在shell环境中可以操作的命令或者是可执行文件 |
2 | 系统核心可调用的函数与工具等 |
3 | 一些常用的函数(function)与函数库(library),大部分为C的函数库(libc) |
4 | 设备文件的说明,通常在/dev下的文件 |
5 | 配置文件或者是某些文件的格式 |
6 | 游戏(games) |
7 | 惯例与协定等,例如Linux文件系统、网络协定、ASCII code等等的说明 |
8 | 系统管理员可用的管理指令 |
9 | 跟kernel有关的文件 |
上述的表格内容可以使用“man man”来更详细的取得说明。通过这张表格的说明,未来你如果使用man page在察看某些数据时,就会知道该指令/文件所代表的基本意义是什么了。举例来说,如果你下达了“man null”时,会出现的第一行是:“NULL(4)”,对照一下上面的数字意义, 可以发现原来null是一个“设备文件”。
接下来,man page把内容分为了很多区块来对命令进行详细的介绍,以NAME作为开始介绍,最后还有个SEE ALSO来作为结束。基本上,man page大致分成下面这几个部分:
代号 | 内容说明 |
---|---|
NAME | 简短的命令、数据名称的说明 |
SYNOPSIS | 简短的命令调用语法(syntax)简介 |
DESCRIPTION | 较为完整的说明,这部分最好仔细看看! |
OPTIONS | 针对 SYNOPSIS 部分中,有列举的所有可用的选项说明 |
COMMANDS | 当这个程序(软件)在执行的时候,可以在此程序(软件)中调用的子命令 |
FILES | 这个程序或数据所使用或参考或链接到的某些文件 |
SEE ALSO | 可以参考的,跟这个指令或数据有相关的其他说明! |
EXAMPLE | 一些可以参考的范例 |
有时候除了这些外,还可能会看到Authors与Copyright等,不过也有很多时候仅有NAME与DESCRIPTION等部分。
同时,我们注意到man page其实是一个交互式的文档页面,那么在man page中我们可以利用哪些按键来帮助查阅呢?首先,如果是向下翻页的话,可以使用空格键,同时也可以使用[Page Up]和[Page Down]来进行翻页。同时,如果你想知道某些关键字的话,可以输入/word来对关键字进行搜索,例如在上面的date命令的man page中,我们输入/date之后就会变成下面这样:
可以看到,所有的date都被标位高亮了。man page中常用的按键如下所示:
按键 | 动作 |
---|---|
空格键 | 向下翻页 |
Page Down | 向下翻页 |
Page Up | 向上翻页 |
Home | 去第一页 |
End | 去最后一页 |
/string | 向“下”搜寻 string 这个字串,如果要搜寻 laomst 的话,就输入 /laomst |
?string | 向“上”搜寻 string 这个字串 |
n, N | 利用 / 或 ? 来搜寻字串时,可以用 n 来继续下一个搜寻 (不论是 / 或 ?) ,可以利用 N 来进行“反向”搜寻。举例来说,我以 /laomst 搜寻 laomst 字串, 那么可以 n 继续往下查询,用 N 往上查询。若以 ?laomst 向上查询 laomst 字串, 那我可以用 n 继续“向上”查询,用 N 反向查询。 |
q | 结束这次的 man page |
我们一定要掌握命令的–help选项和man page的使用,这样我们就不用硬记所有命令的用法了,只需要记忆比较常用的命令的用法,对于不常用的,在需要的时候进行查阅就可以了。
Bash内建命令
如果我们对cd使用–help选项,会接到如下的错误提示:
这说明cd命令是不支持–help选项的,那么我们就只能使用man cd来查看cd命令的文档:
当我们查看cd命令的man page的时候发现,NAME段包含了非常多的命令,而接下来的一行是BASH BUILTIN COMMANDS。意思是Bash内建命令。
实际上,为了方便Shell的操作,Bash已经内置了很多的命令,上面的cd命令就是其中之一。
那么我们怎么知道一个命令是Bash的内置命令还是系统命令呢?我们可以用type [-tpa] name
这个命令来进行观察,如下:
我们可以清楚地看到,cd是Bash的内建命令。type命令在不加任何选项的时候,会返回这个命令是否是一个内部命令,而type具有三个常用的选项,分别是-t、-p和-a,它们的含义如下:
-
-t:type将能够查到到的第一个name(内建命令的优先级最高)以下列字眼显示出它的意义:
- file,表示name为一个外部命令
- alias,表示该命令为命令别名设置的名称
- builtin,表示该命令为bash内置的命令
-
-a:显示出所有的能够从PATH中查找到的name,包括alias
-
-p:如果后面接的命令为外部命令时,才会显示完整的路径名,否则什么都不会显示
几个重要的热键
在进行接下来的学习之前,还有一个重要的点需要说明提一下,那就是Bash里面有很多的功能组合键,这些组按键可以辅助我们进行命令的书写和程序的中断。这些功能键都是非常常用的。
-
Tab
在各种Unix-like的Shell中,[Tab]键算是Bash Shell最棒的功能之一,它具有命令补全与路径补全的功能,重点是它可以有效避免我们打错命令或者是路径名。需要注意的是,**[Tab]**在不同的上下文中输入具有不同的功能,总的来说有如下三种情况
- [Tab]接在一串命令的第一个单词中,则为命令补全
- [Tab]接在第二个单词或者之后的单词中,则为路径补全
- 如果安装了Bash-completion软件,则在某些命令后面使用[Tab]按键可以进行选项或者参数的补全
-
Ctrl+C
如果我们输入命令的时候发生了错误,想要重新输入,或者是当我们开始运行一个命令之后,由于种种原因(比如网络不好等),命令一直运行无法结束,这个时候我们可以使用Ctrl+C来对命令进行中断。
不过需要注意的是,Ctrl+C会中断正在执行的命令,如果我们正在执行的命令比较重要,就不要急着使用这个组合键,让子弹先飞一会。
-
Ctrl+D
Ctrl+D通常意味着键盘输入结束(End Of File,EOF或End Of Input)。另外,它也可以用来取代exit的输入。
-
Shift+[Page Up] 或者 Shift+[Page Down]
如果你在纯文本的画面中执行某些命令,而这个命令的输出信息想当长,导致前面的部份已经不在目前的屏幕画面中,这个时候如果你想回过头去看一看输出信息,则可以使用 [Shift]+[Page Up] 来往前翻页,也能够使用 [Shift]+[Page Down] 来往后翻页。
命令提示符
在我们刚刚使用命令行进入linux系统但是还什么都没有输入的时候,命令行却不是空白一片,而是已经在跟登录的用户打招呼了,如下:
我们还什么都没有输入呢,但是命令行却已经输出了一行的内容,这就是终端跟我们打招呼的方式,我们称之为"命令提示符", 它为我们展示了一些基本的信息
这个信息包含三个方面的内容
-
用户名:@符前面的就是使用当前终端登录系统的用户的用户名
@符号其实就是英文中的’at’,因为在当代的计算机中,我们经常需要表示一个资源的位置,所以这个符号才被创造了出来,同时他的意思也是‘在…位置’的意思
-
主机名:@符号后面,:前面的部分就是主机的名称
-
当前的工作目录:
:
后面$
之前的部分表明了当前所在的目录命令提示符的上面三个部分连起来的意思就是:当前终端的用户是laomst,所在的位置是名为VM-16-15-centos的主机的~目录下,其中
~
目录代表用户的home目录 -
权限提示符:
$
代表的是laomst用户在VM-16-15-centos主机的~目录下所具有的权限,权限一共有两种情况,一种是$
,意思是普通用户,还有一种是#
,意思是root用户权限命令提示符的所有内容连接起来的意思就是:你适用laomst用户登录VM-16-15-centos主机,当前所在的目录是~,拥有普通用户的有限权限。
我们需要注意的是,不同的Shell命令提示符的内容可能不太相同,但是它们的命令提示符的基本元素都是一样的,只不过是展现出来的方式稍有差别。
当然了,命令行提示符所显示的内容是可以自己进行配置的,感兴趣的同学可以自行研究一下。
临时切换到root用户
在我们平时使用Linux系统的时候,不建议直接以root用户登录shell,而是建议使用普通的账号进行登录。这其实是一种简单的保护措施,大大地提高了 Linux 系统的安全性,有效防止误操作或是病毒的攻击。甚至Ubuntu 系统(Linux的一个发行版)默认不允许以 root 用户登录系统。
但是,当我们运行某些命令的时候又需要root权限,这需要怎么做呢?难道需要注销当前的用户然后使用root用户重新进行登录?
在linux中是不用这么麻烦的,我们可以sudo命令用当前的账号以root身份来运行这样的命令,比如我们以root身份运行date命令:
上面的方式是临时以root身份执行某一条命令,如果我们需要连续多次执行需要root权限的命令,那么这种方式就不是特别方便,这个时候我们可以使用sudo su
命令直接把当前用户的身份切换成root:
可以看到,在切换到root用户之后,权限提示符从$
变为了#
,当我们操作完成之后,如果想要退出root用户,回到原来的用户身份,值需要使用 Ctrl+D组合键或者exit命令退出 sudo就可以了。
总结
这篇文章中我们简单介绍了命令调用的基本语法,重点介绍了调用命令时OPTIONS的写法,同时说明了一些在使用Bash时必须注意的事项和比较常用的技巧。
随着我们对Bash使用的不断深入,我们后续的文章会介绍更多的Bash的高级特性。
感谢你耐心读完。本人深知技术水平和表达能力有限,如果文中有什么地方不合理或者你有其他不同的思考和看法,欢迎随时和我进行讨论(laomst@163.com)。