Linux:命令行是你的至交好友
July 10, 2015
命令行既可以成为你的至交好友,又可能成为你最大的敌人。它关键取决于你怎样用它,以及用它来做什么。如果你还是像大部分人一样畏惧使用命令行界面,那么这篇文章定会让你受益匪浅。
Table of Contents
命令行界面?
是的,它是在黑色屏幕上的白色(或者绿色)的显 示区域,是神秘的文字流和奇怪的命令执行的地方。我知道很多大师级的程序员从来不使用命令行界面;然而,我也知道一些初级用户用命令行来做所有的事而不是 用图形界面。他们控制应用程序去浏览网页和文件系统,查收邮件,查看图片和编辑文字。他们甚至看youtyube视频和查看PDF文件都不使用图形界面!
最好的工作流程是取决于个人的。有些人倾向于图形界面,其他人则钟爱于命令行。
术语
刚刚接触Unix或者Linux的人在面对诸如终端,控制台和shell时是比较困惑的。
从用户的角度来看,它们之间似乎是没有太大区别的,但事实上,用户是使用控制台来连接终端来查看运行在计算机上的脚本。
在过去的时候,这三者是独立的硬件。控制台无非是一个显示器和一个键盘;它没有计算能力。它通过一个串行接口去连接终端,应用最广泛的是RS-232接口。
终端就像大型主机的界面。它一般具有计算、网络通信或进行其他特殊连接,如与大型主机连接的能力。终端也提供了对系统的管理者权限,这也是它为什么总是被 关在小黑屋的原因。被雇用者使用连接到这些终端的控制台进行工作,但是却无法获得大型主机的管理者权限。控制台与终端最终合并为一个单独的设备,最好的例 子的就是现代linux发行版中仿真的虚拟机终端。
shell就是一个可以读取用户输入,然后在屏幕输出结果的程序。一个shell可以是基于字符的(像CLI),或者是基于图形的(像Windows的 GUI)。今天,shell已经不仅仅是用户与系统的接口,他还肩负着管理进程,窗口,应用程序,命令,以及系统的其他方面。
shell解释执行命令行中输入的命令,用户也可以将命令组合起来写成一个脚本。现代的shell拥有自己的脚本语言,这提供了执行复杂任务的能力。
大多数现代的Linux发行版,如同Mac OSX一样,使用一个shell,BASH(译注:默认的,想用什么自己换)。Solaris和OpenIndiana默认使用Korn Shell,一个BASH的变种。请注意这篇指南主要讲的是BASH。
让我们说说 BASH
BASH 代表 Bourne Again Shell。它被作为 Bourne Shell 的新版本于1989年发布,之后成为了 Unix 系统的默认 shell。它由斯蒂芬·伯恩(Stephen Bourne)编写,用以取代 Thompson Shell。老版的 Bourne Shell 至今仍工作在一些 Unix 系统中。通常你可以用 /bin/sh 找到它。总之,尽管 Bourne Shell 在新的 Linux 发行版中 已经为 BASH 取代,/bin/sh 和 /bin/bash 都能被 BASH 运行。
BASH的提示符
你永远都会碰到BASH的提示符。它是一个贯穿BASH及其历史的东西。如果篇幅允许,我们可以用所有篇幅讲讲如何按自己的希望配置BASH的提示符。但是,我们只会在这个指南中提到一些基本的东西。
csaba@csaba-pc ~/Personal/Programming/NetTuts$
我的BASH提示符就像上面那个样子。 第一个词csaba是我的用户名,后接@和我的主机名称,最后是当前的文件夹。~这个字符代表了用户文件夹,对于我来说是/home/csaba。整行以$结尾,在$后面输入的东西是我想shell执行的命令。
当然,这仅仅是一个简单的例子。你可以放更多的东西进提示符中。来看看更多的例子吧。
PS1,PS2,PS3和PS4是BASH的特殊变量,它们控制着不同类型的提示符(例如PS2是一般使用于命令行里较长命令的换行提示信息)。我们在这篇指南中只用到PS1。你可以用下面的命令查看你的PS1变量。
csaba@csaba-pc ~/Personal/Programming/NetTuts $ echo $PS1 \[\033[01;32m\]\u@\h\[\033[01;34m\] \w \$\[\033[00m\]
输入命令echo $PS1,然后你就看见了我的PS1变量。在BASH中,我们将$到变量名称前就可以得到这个变量的内容。这个echo命令仅仅会输出它接到的参数。我们给echo的参数是变量的值,所以它会输出这个变量的值。
输出代表着一种格式。\[\033[01;32m\]表示绿色,\u表示当前用户的用户名。\h表示主机名,\[\033[01;34m\]表示蓝色,\w是当前目录,\[\033[00m\]是将文字后续输入的文字置为高亮灰色。通过下面的屏幕截图你能够更好地理解结果。
以“\”开头的特殊字符具有特别的意义。反之“\”标识后面的字符是一个转义字符(比如颜色代码)。下面的内容是从BASH官方手册中引用的,你可以在BASH命令中使用的特殊字符的完整列表:
- \a- ASCII响铃字符(07)
- \d– 以“Weekday Month Date”格式显示日期
- \D{format}– format被传递给strftime(3)并把相应的结果插入到提示字符串中; 如果format为空则代表本地时间. 必须有在括号
- \e– ASCII转义字符(033)
- \h– 到第一个 `.’前代表主机名称
- \H– 主机名称
- \j– 当前被Shell管理工作数
- \l– Shell终端设置名称的基本名
- \n– 新行
- \r– 回车
- \s– Shell的名称
- \T– 12小时制当前时间,格式为 HH:MM:SS
- \t– 24小时制当前时间,格式为 HH:MM:SS
- \@– 12小时制当前时间,格式为am/pm
- \A– 24小时制当前时间,格式为 HH:MM
- \u– 当前用户的名称
- \v– BASH版本
- \V– BASH发行备注,版本号+补丁
- \w– 当前工作目录,其中$HOME被缩写成”~”(使用PROMPT_DIRTRIM的值)
- \W– 当前工作目录的basename,$HOME被缩写成”~”
- \!– 命令的使用次数
- \#– 命令号
- \$– 命令提示符,如果UID是0则显示为#,否则为$
- \nnn– 8进制数据nnn代表的字符
- \\– 反斜杠
- \[- 开始一个非打印字符序列,这个序列可以嵌入一个终端控制序列到提示中
- \]– 非打印字符序列结束
操作目录和文件
在命令行环境中,每个人都要做的一件事就是操作文件系统,创建,删除,复制和移动文件系统对象,并且执行命令。这对你来说可能已经是家常便饭,然而,还是让我们来看一眼:
csaba@csaba-pc ~ $ mkdir ~/tmp/NetTuts csaba@csaba-pc ~ $ cd ~/tmp/NetTuts/ csaba@csaba-pc ~/tmp/NetTuts $ mkdir ./AnotherDir csaba@csaba-pc ~/tmp/NetTuts $ mkdir ./SecondDir csaba@csaba-pc ~/tmp/NetTuts $ touch ./SecondDir/aFile csaba@csaba-pc ~/tmp/NetTuts $ touch ./SecondDir/AnotherFile csaba@csaba-pc ~/tmp/NetTuts $ cd ./SecondDir/ csaba@csaba-pc ~/tmp/NetTuts/SecondDir $ pushd ~/tmp/NetTuts ~/tmp/NetTuts ~/tmp/NetTuts/SecondDir csaba@csaba-pc ~/tmp/NetTuts $ ls -al total 16 drwxr-xr-x 4 csaba csaba 4096 Feb 19 21:09 . drwx—— 7 csaba csaba 4096 Feb 19 21:09 .. drwxr-xr-x 2 csaba csaba 4096 Feb 19 21:09 AnotherDir drwxr-xr-x 2 csaba csaba 4096 Feb 19 21:09 SecondDir csaba@csaba-pc ~/tmp/NetTuts $ popd ~/tmp/NetTuts/SecondDir csaba@csaba-pc ~/tmp/NetTuts/SecondDir $ ls -al total 8 drwxr-xr-x 2 csaba csaba 4096 Feb 19 21:09 . drwxr-xr-x 4 csaba csaba 4096 Feb 19 21:09 .. -rw-r–r– 1 csaba csaba 0 Feb 19 21:09 aFile -rw-r–r– 1 csaba csaba 0 Feb 19 21:09 AnotherFile csaba@csaba-pc ~/tmp/NetTuts/SecondDir $
逐句解释:
- 在/home/csaba/tmp下创建一个名为NetTuts的目录
- 将刚刚创建的目录切换为当前目录
- 在当前目录下创建一个名为“AnotherDir”的目录
- 在当前目录下创建一个名为“SecondDir”的目录
- 使用touch命令在“SecondDir”目录下创建两个空文件
- 切换当前目录到SecondDir.
- 使用pushd命令切换目录到~/tmp/NetTuts来把当前目录存储到堆栈之中
- 列出目录~/tmp/NetTuts下的所有文件
- 使用popd命令来返回前一个目录,这样会从堆栈中获取并且移除最顶层的目录
- 再一次列出内容会看到我们上几步所创建的两个文件
当然,对于命令行你们可以有个万能文件管理器,称之为Midnight Commander。要开始用的时候只需要执行它的命令就行。它也内置了文本编辑器(高亮代码的那段)适合大部分语言,而且有智能缩进和其他的一些特性。 它不完全是一个被夸大的编辑器,事实上,它是一个相当简单的工具,特别适合简单和快速编辑。你可以随意的选择任何文件然后按F4,或者你可以在编辑模式下 直接打开一个文件。
csaba@csaba-pc ~/tmp/NetTuts/SecondDir $ mcedit ./aFile
输入/输出
每个命令必须和命令行环境交互。命令需要输入和提供输出。
标准输入是命令读取信息的来源。键盘是默认标准输入,标准输入经常被称为“stdin”。
标准输出是命令的输出会被发送到的地方。默认是当前控制台,标准输出通常被称为“stdout”。
标准错误是命令输出错误的地方。默认当前控制台,常被称为”stderr”。
到目前为止,我们可以定义简单的状态,来表示一个命令从键盘上读取并输出它的结果(包括好的和坏的)到屏幕上.
在Unix(或类unix系统)中, 所有的东西都会被抽象成文件,你的键盘是文件,你的鼠标是文件,你的屏幕是文件,程序是文件, 文本是文件,等等
文件描述符是一个整形数字用于操作系统引用打开的文件, 所有的unix系统至少包含三个文件描述符.
- 描述符 no. 0 – 标准输入
- 描述符 no. 1 – 标准输出
- 描述符 no. 2 – 标准错误输出
重定向
Unix系统有一个非常强大的特性:因为所有资源都是文件,你可以将所有资源引用和将其从一个位置重定向到另一个位置。重定向的操作符表示标准输出(stdout)。所以,如果你需要一个命令从键盘中读取信息,你可以进行如下操作:
$ someCommand <
但当要你的命令从一个文件中读取内容你要怎么做呢?你只要重定向这个文件到它的标准输入(stdin),如下:
$ someCommand < /your/file.txt
如果你要你的命令执行结果输出到一个文件,你可以使用>操作符。例如我们已经知道如何将一个目录中的文件列出:
csaba@csaba-pc ~/tmp/NetTuts/SecondDir $ ls -al total 8 drwxr-xr-x 2 csaba csaba 4096 Feb 19 21:09 . drwxr-xr-x 4 csaba csaba 4096 Feb 19 21:09 .. -rw-r–r– 1 csaba csaba 0 Feb 19 21:09 aFile -rw-r–r– 1 csaba csaba 0 Feb 19 21:09 AnotherFile csaba@csaba-pc ~/tmp/NetTuts/SecondDir $
你可以把使用如下命令将结果发送到一个文件:
csaba@csaba-pc ~/tmp/NetTuts/SecondDir $ ls -al > ./ThirdFile
ThirdFile的内容如下:
total 12 drwxr-xr-x 2 csaba csaba 4096 Feb 24 00:06 . drwxr-xr-x 4 csaba csaba 4096 Feb 19 21:09 .. -rw-r–r– 1 csaba csaba 12 Feb 19 21:19 aFile -rw-r–r– 1 csaba csaba 0 Feb 19 21:09 AnotherFile -rw-r–r– 1 csaba csaba 0 Feb 24 00:06 ThirdFile
比方说,我们要导航到上级目录,列出它所有的文件,并且使用一个命令将这个列表添加至一个已经存在的文件中。操作符>重定向输出到一个文件并且覆盖该文件;所以我们不能使用它。不过,我们可以使用>>(两个>)来添加新数据到一个已经存在的文件。
csaba@csaba-pc ~/tmp/NetTuts/SecondDir $ cd .. csaba@csaba-pc ~/tmp/NetTuts $ ls -al total 16 drwxr-xr-x 4 csaba csaba 4096 Feb 19 21:09 . drwx—— 7 csaba csaba 4096 Feb 19 21:09 .. drwxr-xr-x 2 csaba csaba 4096 Feb 19 21:09 AnotherDir drwxr-xr-x 2 csaba csaba 4096 Feb 24 00:06 SecondDir csaba@csaba-pc ~/tmp/NetTuts $ ls -al >> ./SecondDir/ThirdFile
于是我们的文件内容就是这样了:
total 12 drwxr-xr-x 2 csaba csaba 4096 Feb 24 00:06 . drwxr-xr-x 4 csaba csaba 4096 Feb 19 21:09 .. -rw-r–r– 1 csaba csaba 12 Feb 19 21:19 aFile -rw-r–r– 1 csaba csaba 0 Feb 19 21:09 AnotherFile -rw-r–r– 1 csaba csaba 0 Feb 24 00:06 ThirdFile total 16 drwxr-xr-x 4 csaba csaba 4096 Feb 19 21:09 . drwx—— 7 csaba csaba 4096 Feb 19 21:09 .. drwxr-xr-x 2 csaba csaba 4096 Feb 19 21:09 AnotherDir drwxr-xr-x 2 csaba csaba 4096 Feb 24 00:06 SecondDir
输入/输出重定向
我们可以综合我们的知识,以不同的方向重定向标准错误(stderr),标准输入(stdin)和标准输出(stdout)。实际上,以下的命令功能相同:
csaba@csaba-pc ~/tmp/NetTuts $ ls -al > ./SecondDir/ThirdFile csaba@csaba-pc ~/tmp/NetTuts $ ls -al 1> ./SecondDir/ThirdFile
在第二个命令中,在重定向之前我们指定标准输出的来源。请注意1与>之间没有空格。实际上,如果两者之间有空格,则1会作为ls命令的一个参数,并且>会自动重定向标准输出。以下两个表达功能相同,但和上面的那个功能不同。
csaba@csaba-pc ~/tmp/NetTuts $ ls -al 1 > ./SecondDir/ThirdFile csaba@csaba-pc ~/tmp/NetTuts $ ls -al 1 1> ./SecondDir/ThirdFile
当然,这些结果会出错:”ls:不能访问1:没有那个文件或目录” ——除非你真的有一个名字为1的目录。这会让我们惊讶下一步我们得到的:重定向错误。
csaba@csaba-pc ~/tmp/NetTuts $ ls -al inexistenFilder > ./SecondDir/ThirdFile ls: cannot access inexistenFilder: No such file or directory csaba@csaba-pc ~/tmp/NetTuts $ ls -al inexistenFilder 2> ./SecondDir/ThirdFile
如你所见,第一个命令在控制台输出标准输出并重定向标准输出到一个文件。第一个命令的结果是一个空文件和屏幕上的一条信息。然而,第二条命令重定向错误到我们的文件。其结果是如果在标准输出上有任何输出,则它们会显示在屏幕上,并且错误信息会输入到这个文件。
一个实际的I/0重导例子
当你需要在命令行寻找一些文件时,你基本上只有两个选择。第一个就是选择用本地命令。这些命令常常是伴随着安装各种Linux版本而已经安装好的,当然不 是每一个版本都安装了。更新文件数据库命令索引你的文件和定位,然后使用那个数据库去发现你的文件。实际上他不是做一个实时的搜索,它只是简单的在数据库 做索引。这就是为什么这个应用程序常常定期的做每日更新文件数据库。
我们来用这个命令演示一个实时搜索,它比本地命令搜索的更精确,但是很显然更慢一些。现在让我们用这个命令来演示一段:
csaba@csaba-pc ~/tmp/NetTuts $ ls -al total 16 drwxr-xr-x 4 csaba csaba 4096 Feb 19 21:09 . drwx—— 7 csaba csaba 4096 Feb 19 21:09 .. drwxr-xr-x 2 csaba csaba 4096 Feb 19 21:09 AnotherDir drwxr-xr-x 2 csaba csaba 4096 Feb 24 00:06 SecondDir csaba@csaba-pc ~/tmp/NetTuts $ ls -al ./SecondDir/ total 16 drwxr-xr-x 2 csaba csaba 4096 Feb 24 00:06 . drwxr-xr-x 4 csaba csaba 4096 Feb 19 21:09 .. -rw-r–r– 1 csaba csaba 12 Feb 19 21:19 aFile -rw-r–r– 1 csaba csaba 0 Feb 19 21:09 AnotherFile -rw-r–r– 1 csaba csaba 61 Feb 24 00:23 ThirdFile csaba@csaba-pc ~/tmp/NetTuts $ find . -name ThirdFile ./SecondDir/ThirdFile
我打印这两个ls命令是为了让你很方便的看明白目录结构,第三个是find命令。它有着复杂的参数系统,在此我就不一一列举了,但是以上的例子展示了find命令最常见的使用。第一个参数.是一个我们想去搜索的目录。
小贴士:参考当前目录……参考上目录
find命令的第二个参数是-name,紧接着是文件的名字。在-name参数中我们可以用?和*来扩大我们的搜索范围:
csaba@csaba-pc ~/tmp/NetTuts $ find . -name ?File ./SecondDir/aFile csaba@csaba-pc ~/tmp/NetTuts $ find . -name *File ./SecondDir/aFile ./SecondDir/AnotherFile ./SecondDir/ThirdFile
?代表一个单个字母,而*指的是任意的字母数量。
接下来,我们将创建一个目录同时使它被我们的用户所不能读。我们还没有讲解到权限,但是不用着急,很快我们将涉及那部分。现在试试下面的例子:
csaba@csaba-pc ~/tmp/NetTuts $ mkdir ThirdDir csaba@csaba-pc ~/tmp/NetTuts $ chmod 000 ThirdDir csaba@csaba-pc ~/tmp/NetTuts $ find . -name *File ./SecondDir/aFile ./SecondDir/AnotherFile ./SecondDir/ThirdFile find: `./ThirdDir’: Permission denied
在这个例子中,我希望你对这目录没有权限以便我可以展示一下find输出的内容。它试着进入到所有的目录中然后搜索所有匹配的文件。当它不能进入一个目 录,它会输出一条信息。当你看到一两条这样的信息提示是很正常的哈,但是作为一个普通用户去试着搜索root目录下面的文件时。你将会获取数百条错误信息 提示而且可能只有一两条搜索结果。你不想错过搜索结果;于是乎你想要除去错误的信息提示。
csaba@csaba-pc ~/tmp/NetTuts $ find . -name *File 2> /dev/null ./SecondDir/aFile ./SecondDir/AnotherFile ./SecondDir/ThirdFile
我们重定向标准错误输出到/dev/null里面。这样做再好不过了。无论你向/dev/null扔进去什么东西,它都可以很简单的使他消失。通常的做法 是当你不想看见这些错误提示信息,你可以把信息发到那里。假如你更喜欢把结果存入一个文件中的话,你可以把错误提示信息传送到/dev/null,然后可 以用多道重定向:
csaba@csaba-pc ~/tmp/NetTuts $ find . -name *File 2> /dev/null 1>./SecondDir/ThirdFile csaba@csaba-pc ~/tmp/NetTuts $
正如你看见的,这个命令在屏幕上面什么也没有输出,因为错误信息和标准输出被传送到了不同的文件中。但是如果我们想在同一个文件中看到两种信息的输出,怎么办呢?没问题,你可以把标准错误输出传送到标准输出然后把标准输出传送到文件中:
find . -name *File 1>./SecondDir/ThirdFile 2>&1
重定向被解释执行是从右到左的。首先开始执行的是 2>&1,这里的意思是重定向标准错误输出到标准输出。然后是1>./SecondDir/ThirdFile,这里的意思是重定向标准输出(此时已经有错误信息在文件里面了)到指定的文件。
0 Comments