一直很困惑很多人都说在Linux上命令行是极有用处和极好用的。对于前者,本人表示赞同,的确在Linux上离开命令行简直没法活了。但是好用就要打个问号了。首先,对于刚刚开始使用的人根本就不知道要使用什么命令。随便从网上找几个apt-get之类的命令,用了也是知其然不知其所以然的。然后于是乎到网上搜索一番,找到一大堆的常用命令。然而似乎也并没有什么用。就拿ls命令来说,对于日常工作似乎并没有什么实际用处。类似的工作,用图形界面不是更好么。


但是不管怎么说,命令行就在那里,不管我们懂不懂,喜不喜欢,他就在哪里。一番回忆和搜索之后,本人似乎这儿题目似乎有了一些解。


一、终端


要玩转命令行,让一切了然与心。需要先清楚一些概念。


首先是tty。玩过Linux内核的人都知道tty,知道tty是一种内核文件。但是tty的来源以及定义却未必是人人都清楚的。


这里首先说终端和控制台。早期计算机是由多人共享使用的。每个人使用一种设备和主机建立链接,然后使用主机的资源。这种设备就被称作终端。它用户输入,并将其发送给主机,并显示主机返回计算结果。因为终端是给多人使用的,是在主机启动之后才和主机建立链接的,所以需要另外一种设备可以完全控制主机。这种设备就叫控制台。控制台是直接连接到主机的,属于主机的一部分。开机的时候,主机会把一些信息打印到控制台上,但是不会打印到终端。一台主机可以有很多终端,但是只会有一个控制台。后来,随着PC的出现,人们使用电脑的方式出现了变化。控制台和终端演化成了软件的概念,他们又被称作虚拟控制台和虚拟终端。


现在Linux还提供5个基于命令行的虚拟终端(分别通过Ctrl+Alt +F2~F6进行切换),一个图形虚拟终端(Ctrl+Alt+F7进行切换),以及一个虚拟控制台(Ctrl+Alt+F1)。这就是在模拟当初多人使用同一台主机的场景。不过在Linux中这个控制台和其他终端之间的区别已经非常模糊了。比如在第2个虚拟终端执行以下命令:


        echo "hello,world" > /dev/console


“hello world”会被显示在当前屏幕


最早出现的终端设备,是由TeleType生产的,据说类似于“电传打字机”。不过本人也没见过电传打字机,也只能臆想一下了。这些设备也就是称作tty,大约是teletypes或teletypewriter的缩写。后来tty也就泛指各种终端设备了。打开./dev会看到远超7个的tty文件(tty0~tty63),个人理解对于PC是没什么用的,因为一般情况不会有那么多终端链接到主机。

wKiom1eseq7RXBUiAAGLH0TcaCQ452.png-wh_50


在Ubuntu下使用命令行有两种操作方式。一种是使用Ctrl+Alt+F1~F6在各个终端之间切换。另外一种是在图形界面环境下打开一个命令行窗口。在这两种方式有区别吗?当然有。在图形界面下打开的命令行窗口不是终端,而是叫做终端模拟器,也叫伪终端。伪终端的工作方式是这样的:

wKiom1esewCSOkMFAABYgYjuJ68311.png-wh_50


可以把伪终端从设备看成是传统的中终端设备,而把伪终端主设备看作数据读写的接口,就可以理解了为什么伪终端用来提供图形界面或网络环境下的终端模拟了。


这类可以看出×nix内核的灵活性了。不用另起炉灶,只需增加两种不同的设备文件就实现了远程终端。


话说多了。那究竟使用那种方式好呢?个人认为是伪终端比较好了。首先,使用伪终端的同时还可以使用图形界面。无论好坏,图形界面在某些情况下还是有优势的,不能全盘否定,哪怕是在Linux上。其次,伪终端对于个人用户来说在某种程度上可以说没有个数限制,想开多少个就开多少个,个人认为这个东西是×××。这里我们终于不用纠结或者内心愧疚在Linux下没有使用 纯命令行界面了。


现在常见的虚拟终端软件有:xterm、rxvt、lxterminal、terminal


二、命令行,为什么?


说了半天终端的原理和历史,但是终端对于使用者而言只是一个黑黑的屏幕,和Windows上的命令行看起来差不多。并不能体现出Linux命令行的强大易用。就目前而言,也只是搞清楚了不必抛弃图形界面,因为在图形接界面环境下命令行窗口想有多少个就有多少个。


思来想去,个人认为Linux命令行之所以强大和这样一些东西有关:终端、Shell、标准输入输出、管道、多进程架构、文化(又是文化……)。


Linux中每个终端有一个输入队列和输出队列,每个进程会有三个流(stdin、stdout、stderr)。当从终端运行一个程序时,系统将进程的标准输入输出流连接到终端的输入输出队列。如下图:

wKioL1ese0-T4o5gAAA_MTSgTMI355.png-wh_50


然后键盘输入就变成了进程标准输入(stdin),屏幕则接受进程标准输出(stderr)和标准错误(stderr)。这就是Linux中命令行的工作方式,也叫终端IO。这种工作方式需要进程和终端之间的配合,以及程序对标准IO进行处理。没有什么特别神奇的地方,Windows中也是一样,进程可以通过标准输入从命令行读取数据,然后通过标准输出将结果输出给命令行。但是问题是Windows有多少程序使用标准输入输出呢?恐怕大多数程序都没有进行这方面的处理吧。


当然程序对标准输入输出进行处理只是命令行的基础,还谈不上好用和强大。Linux中命令行的第二种方式是使用输入输出重定向,也就是管道。当执行一个进程,进程的输出被重定向到另一个进程作为其输入。如下图:

wKiom1ese73BT2gkAABGPsG3GgY426.png-wh_50


管道将命令ls的输出送给wc命令进行统计


其实这个也不是特别神奇,因为在Windows上也有管道,也一样可以进行输出重定向。


要命的东西是多进程。在Linux上,进程相对Windows来说比较轻量级。所以Linux程序多采用多进程架构,进程间通过管道进行通信。一个任务往往是由多个进程之间协同完成的。这个时候标准IO和管道就特别有用了。而在Windows上进程比较重,一般的程序都不采用多进程,而是在必要的时候使用多线程。也就是说在Windows上通常不进行进程间协作,而是每个进程独立提供所有功能和独立完成所有任务。而更有甚者的是很多Windows程序根本不使用标准输入输出,因为不需要和其他进程协作。


这是两种不同的设计理念,无所谓好坏。但是多进程+管道的模式的确是能在命令行环境下发挥出强大的为例。而在计算机性能不是那么好的当年,单进程/多线程架构在用户体验上也似乎能够提供更好的响应速度(其实为了提高图形界面的响应速度,Windows甚至将GUI放在内核态,也是蛮拼的)。


标准IO+管道+多进程的好处有很多,个人认为还有一个比较重要的就是软件复用。一个软件只要定义好了标准IO就可以很容易的为其他软件提供服务了,这么一来复用他人的软件就比较容易了。相对而言图形界面就没有这个优势。基于标准IO的软件复用的容易程度提升了大家对软件复用的共识,而软件复用的共识又进一步增强了软件的复用度,进而形成了文化。而这一切都是基于命令行的,在这种形式下命令行想不强大都不行啊……


个人觉得,这个多进程架构+管道+终端的模式是导致Linux上图形界面用户体验不佳的重要原因之一。不是因为技术,而是大家都把注意力放在了标准IO的处理以及软件复用上,对图形界面的关注度根本不够。


当然这一切看起来非常美好的架构最后是要依靠Shell来实现的,比如前文的ls| wc -l,就是Shell负责组组合起来的。Shell的衍生品Shell编程,更是让命令行如虎添翼,成了Linux上编程的必学课程。


三、基础命令


总算是感觉连猜带蒙的自圆其说了为什么Linux上命令行强大无比了,无论怎样也要求个下心安理得先。


在使用Linux的过程中关于命令行,除了前面讨论的外,本人的有两大困惑。一是如果要完成一件事该区使用什么命令,去哪里能够找到?二是这些命令的名字都好奇怪啊,完全看不懂

关于后者,下面是本人一番搜索后的结果:

命令

说明

sudo

是系统管理员让普通用户执行一些root命令的程序。基本可以理解成在要执行的命令前加上sudo就表示以root权限执行该命令。这里设计到另外一个命令:su。su可以用来临时切换到root用户,su有个安全隐患,所以人们在su的基础上发明了sudo。相对来说sudo的优势在于:需要授权(权限不是无限的),以及使用时不需要知道root账户的密码。

英文:su->switch user

apt-get

适用于使用deb包管理系统的Linux发行版本。用于从互联网的软件仓库中搜索、获取、安装、卸载软件。

英文:Advance Package Tool

dpkg

dpkg本身是一个底层工具,前面的apt就是基于dpkg从远程获取和安装软件包的

英文:debian package

cd

切换当前目录

英文: change directory

pwd

打印当前工作目录

英文:Print Working Directory

man

命令帮助文档。还有就是无论什么其他命令都可以忘记,但是这个不能忘。

英文:manual

ls

列出目录中的文件

英文:list

shutdown

关机

logout

注销

tree

显示文件和目录由根目录开始的树形结构

mkdir

创建目录

英文:make ddirectory

rm

删除目录或文件

英文:remove

cp

复制目录或文件

英文:copy

find

搜索文件或目录

chmod

设置文件权限

英文:change mode

fg

将程序切换到前台运行

pg

将程序切换到后台运行

jobs

显示所有在后台运行的应用

ps

ps

进程状态

英文:process state


可能是为了满足在命令行中输入要尽量精简的需求,这些命令大量用了缩写。结果就是初次使用的时候一头雾水啊。有些缩写完全具有误导性,比如pwd,看起来更像是和设置密码有关的命令。看来还真是没事要多用man看看命令帮组文档。


另外这里有个使用心得也是关于man的。执行命令:


man [软件名称]


能够获得该软件的相关命令帮组,毕竟强大的命令行文化需要有强大的命令行工具和足够的文档,否则拿到一个新程序鬼才知道该怎么去用呢。

wKioL1esfC6yvIb-AAEWRdP4qYA750.png-wh_50


四、快捷键


命令行的确强大,但是如果没有一些快捷键根本抖不起来。下面是本人搜集的一些常用快捷键:

快捷键 说明

↑ 或 Ctrl+p

显示上一条命令

↓ 或 Ctrl+n

显示下一条命令

→ 或 Ctrl+f

光标向右移动一个字符

← 或 Ctrl+b

光标向左移动一个字符

Alt+f

光标向右移动一个单词

Alt+b

光标向左移动一个单词

Ctrl+r

逆向搜索包含输入字符串的命令

Ctrl+s

正向搜索包含输入字体串的命令

Ctrl+a

光标移动到开头

Ctrl+e

光标移动到结尾

Ctrl+l

清屏

Ctrl+u

剪切光标所在处之前的所有字符 (不包括自身)

Ctrl+k

剪切光标所在处之后的所有字符 (包括自身)

Ctrl+w

剪切光标所在处之前的一个词 (以空格、标点等为分隔符)

Ctrl+y

粘贴

Alt+u

将光标所在处的单词转为大写 (从光标处到词的结尾)

Ctrl+c

中断命令

Ctril+z

挂起当前应用


五、更多


前面提到在图形界面环境下可以开多个命令行窗口轻松实现多任务。那么非图形界面下如何执行多任务呢?这个问题一度困惑本人,导致不停的开很多个命令行窗口。在研究命令的时候才发现命令行模式下也是支持多任务的。


通常来说从命令行启动gedit,命令行会直到gedit退出后才能执行下一个命令。如图:

wKiom1esfGPxYzrbAAA__uEvEPA025.png-wh_50


但是如果我们在执行gedit的时候在后面加一个“&”那就情况不同了

wKioL1esfIDghL76AABL3e05tgI282.png-wh_50


哈哈,光标在动。可以无忧无虑的执行下一个任务了。这个就是命令行模式下的多任务。具体设计到的指令有:fg、bg、jobs、ps、kill和快捷键Ctrl+c、Ctrl+z。


Linux命令行果然强大。


六、结束语


当年读关于Linux内核的书的时候看到管道相关的章节浅尝则止草草掠过。因为在Windows下这个东西似乎无足轻重,毕竟没什么人用。但是这次结合命令行以及多进程体系结构看起来,他仿佛是Linux系统的血管了,几乎无处不在把各个程序串联起来。


另外关于命令行这个东西的学习。其实对于技术人员本身而言,大多都是不排斥命令行的。但是常见的Windows开发人员对命令行非常不感冒,究其原因就是没能了解这背后的一整套逻辑:终端+标准IO+管道+多进程。而一旦了解这些逻辑(文化)之后,很容易的就会欣赏这种方式,进而拥抱之。这其实也是一种体验。可惜的是,多年以来本人从未没有看到有论述这方面内容的书籍文章(也许是太低端了,谈Linux必谈内核?)。大多都是以一副普世价值的姿势教导命令行的强大之处,缺少言传身教的耳濡目染,可惜偏偏在感性上命令行是远不如图形界面强大和方便的(在Windows上也的确是如此)。


所以下面本人打算开始探索软件包的管理和程序的执行。这个比搞清楚树形目录文件系统对于使用Linux显得更总要。