在上一篇文章中,我们学习了Linux的基本命令。如果结合使用不同的命令,工作效率可以提高一倍。本文将学习重定向、管道符、通配符、转义符以及重要的环境变量,为后续的shell编程打下基础。一、IO重定向在上一篇文章中,我们已经讲解了近60条常用的Linux命令。上一篇讲解的ls命令查看当前目录下有哪些文件[root@heimatengyuntest]#lstest1.txttest2.txt命令执行后,默认结果输出到电脑屏幕(monitor),但是如果我们想把命令的执行结果保存到一个文件中,方便以后需要的时候随时查阅,怎么办?这需要重定向的知识。1.1重定向概述Linuxshell重定向是指修改系统命令的默认执行方式。我们可以理解为“改变输入输出的方向”,分为输入重定向和输出重定向。既然重定向就是改变默认的输入输出方向,那么默认的输入输出方向是什么?相对于程序而言,用户输入的数据是从键盘读取供程序使用的,即数据从键盘流向程序,是标准输入;程序运行产生的结果数据直接呈现在显示器上,即从程序到显示器的数据流,即标准输出。默认的标准输入输出如下:将默认的从键盘读取数据改为从文件读取数据,即数据从文件流向程序,即输入重定向;程序运行产生的结果数据不显示在显示器上,而是改为输入到文件中,即数据流从程序流向文件,这就是输出重定向。一台计算机的硬件设备有很多。常见的输入设备有键盘、鼠标、麦克风、手写板等,输出设备有显示器、投影仪、打印机等。但是在Linux中,标准输入设备一般指的是键盘,标准输出设备一般指的是显示器。如前所述,Linux中的一切都是文件,包括键盘、显示器等输入输出设备在内的所有计算机硬件都是文件。为了表示和区分打开的文件,Linux会给每个文件分配一个ID。这个ID是一个整数,被称为文件描述符(FileDescriptor)。与输入输出相关的文件描述符如下:文件描述符文件名类型硬件0stdin标准输入文件硬盘1stdout标准输出文件显示2stderr标准错误输出文件显示文件描述符。文件描述符只是一个与打开文件相关联的整数,它可以是硬盘上的普通文件、FIFO、管道、终端、键盘、监视器,甚至是网络连接。默认情况下,stdin、stdout和stderr都是打开的。在重定向过程中,可以直接使用0、1、2这三个文件描述符。1.2重定向分类重定向分为输入重定向和输出重定向。简而言之,输入重定向就是将文件导入到命令中,输出重定向就是将原本输出到屏幕的信息写到指定的文件中。在平时的工作中,输出重定向的使用频率要高于输入重定向。因此,输出重定向又分为标准输出重定向和错误输出重定向。输出重定向分为clearwrite和append两种。模式。标准输出和错误输出请看下面的例子:[root@heimatengyun~]#lstest/test1.txttest2.txt[root@heimatengyun~]#lsxxxls:cannotaccessxxx:Nosuchfileordirectory使用ls命令查看指定目录下的文件信息。如果文件夹存在且文件夹中有内容,则输出文件属主、所属组、文件大小等信息,这是ls命令的标准输出信息。但是如果查看不存在的文件夹,会提示文件不存在的错误信息,这就是ls命令的错误输出信息。如果要将原本输出到屏幕的信息直接写到文件中,而不是显示在屏幕上,就需要区别对待这两类输出信息。1.2.1输入重定向输入重定向相关的符号和功能如下表所示。符号Command文件2使用文件1作为命令的标准输入,标准输出到文件2。输入重定向比较少用。输入重定向的作用是将文件直接导入到命令中。/etc/passwd文件存放系统用户信息,每行记录一个用户。以下示例演示通过输入重定向将此文件导入wc命令以统计用户数。[root@heimatengyuntest]#wc-l?/etc/passwd391.2.2输出重定向输出重定向使用的符号和函数如下表所示。data),1可以省略Command2>file将错误输出重定向到文件(清除原文件数据)command1>>file将标准输出重定向到文件(追加到原内容),1可以省略Command2>>file将错误输出重定向到文件(附加到原始内容)command&>>file将标准输出和错误输出都写入文件(附加到原始内容)command>>file2>&1是一样的如上一条命令:command&>>file对于重定向中的标准输出模式,文件描述符1一般是省略的,但是错误输出模式下的文件描述符2是必须要写的。1.2.3输出重定向示例使用man命令查看如何使用ls命令,将输出信息重定向到ls.txt文件,然后使用cat命令查看ls.txt文件中的信息。[root@heimatengyuntest]#lstest1.txttest2.txt[root@heimatengyuntest]#manls>ls.txt[root@heimatengyuntest]#lsls.txttest1.txttest2.txt[root@heimatengyuntest]#catls.txtLS(1)用户命令LS(1)NAMEls-列出目录内容SYNOPSISls[OPTION]...[FILE]...DESCRIPTION...省略部分内容接下来我们演示clearwrite和appendwritetxt文件(本来是用ls的帮助信息内容),查看内容变化,然后通过appendwrite方式向文件写入一次数据,然后查看文件内容[root@heimatengyuntest]#echo"wellcome">ls。txt[root@heimatengyuntest]#catls.txtwellcome[root@heimatengyuntest]#echo"writemessageagain">>ls.txt[root@heimatengyuntest]#catls.txtwellcomwritemessageagain可以看到overwrite模式会清除文件原来的内容,append模式会在原来的内容后面追加数据。1.2.4标准输出和错误输出的区别虽然都是重定向技术,但是不同命令的标准输出和错误输出还是有区别的。如果一个命令执行成功,通过标准输出输出到文件是没有问题的,但是如果要将错误输出重定向到文件,则不会成功,信息仍然会显示在屏幕上。反之,如果一个命令执行失败,通过error输出到文件没有问题,但是如果输出到标准输出,就不会成功,还是会显示在屏幕上。通过ls命令查看一个已经存在的文件,并将信息重定向到ls.txt文件,查看该文件可以看到存储成功的信息。将其错误输出重定向到ls-err.txt文件。由于正在查看的文件是存在的,没有错误提示,所以屏幕上仍然显示查询成功文件的信息,但是错误重定向的文件中没有任何内容。[root@heimatengyuntest]#lstest1.txttest2.txt[root@heimatengyuntest]#ls-ltest1.txt-rw-r--r--.1rootroot0Nov3015:34test1.txt[root@heimatengyuntest]#ls-ltest1.txt>ls.txt[root@heimatengyuntest]#lsls.txttest1.txttest2.txt[root@heimatengyuntest]#catls.txt-rw-r--r--。1rootroot0Nov3015:34test1.txt[root@heimatengyuntest]#ls-ltest1.txt2>ls-err.txt-rw-r--r--.1rootroot0Nov3015:34test1.txt[root@heimatengyuntest]#lsls-err.txtls.txttest1.txttest2.txt[root@heimatengyuntest]#catls-err.txt命令可以组合以提高工作效率。简而言之,管道符的作用是:将上一条命令原本输出到屏幕的标准普通数据作为下一条命令的标准输入。管道符号用|表示,使用格式为:commandA|commandB|commandC...案例一:统计被禁止登录系统的用户数[root@heimatengyuntest]#grep"/sbin/nologin"/etc/passwd|wc-l34将/etc/passwd文件中的关键字"/sbin/nologin"与《Linux入门系列5--Linux新手入门命令》中介绍的grep命令匹配查找out限制登录系统的用户,并将匹配结果输入wc命令,统计匹配到的行数,即为限制登录系统的用户数。情况二:将文件内容中的小写字母替换成大写字母,输出@黑马腾云测试]#cattest1.txtwellcome通过cat命令读取test1.txt文件的内容导入到tr命令中,通过tr命令将内容中的小写字母替换为大写字母。可以看出,它只是替换读取的内容,对原文件没有影响。tr命令的作用是替换文本文件中的字符。格式为:tr[原字符][目标字符]很多时候你想快速替换文本中的一些词。如果手动替换它们,工作量必然会很大,尤其是当您需要处理大量内容时。这时候tr命令就可以派上用场了,只需将文本内容通过管道符传递给它进行替换即可。ps:上一篇讲了近60条Linux命令。命令太多,无法一一介绍。其余命令将根据场景需要,以案例的形式逐步分散到每篇文章中进行演示。3、通配符通配符的概念存在于很多语言中,如java、c#等,其作用是模糊匹配。假设你的电脑里存了很多小电影,有一天你突然想看某位老师的电影,但是因为文件太多,连电影文件的名字都想不起来了,只能依稀记得那个文件名包含几个关键词,这时候如何快速找到对应的文件呢?面对这种场景,通配符应运而生。熟练使用通配符,电影再多也不会迷路。通配符,顾名思义,是用于匹配信息的通用符号,主要包括以下内容:符号含义*匹配0个或多个字符?匹配单个字符[0-9]匹配0到9之间的单个数字字符[123]匹配指定的三个数字1,2,3中的任意一个[abc]匹配a,b,c三个字符案例1:匹配所有文件其文件名以test[root@heimatengyuntest]#lstest1.txttest2.txt[root@heimatengyuntest]#ls-ltest*-rw-r--r--.1rootroot9Nov3020:43test1.txt-rw-r--r--。1rootroot0Nov3015:34test2.txt案例二:匹配所有最后一位为1或3的文件File[root@heimatengyuntest]#lstest1.txttest2.txt[root@heimatengyuntest]#ls-ltest[13].txt-rw-r--r--。1rootroot9Nov3020:43test1.txt4.转义字符《Linux系列入门之5-新手Linux命令》中提到人与Linux内核的交互是通过在shell终端执行相关命令来实现的,在为了更好地理解用户的表达,除了通配符和管道符外,shell解释器还提供了特别丰富的转义符来处理用户输入的特殊数据。本文仅摘取几个常用的通配符进行说明。转义符及其对应的作用如下:转义符作为一个\反斜杠,使后面的变量成为一个简单的字符串''单引号,将其中的所有字符转义。变量是一个带双引号的简单字符串"",保留里面的变量属性,不进行转义处理``反引号,执行里面的命令,返回结果情况一:输出$$表示的价格[root@heimatengyuntest]#PRICE=99[root@heimatengyuntest]#echo"thepriceis$PRICE"thepriceis99[root@heimatengyuntest]#echo"thepriceis$$PRICE"thepriceis12395PRICE定义PRICE变量保存价格,然后通过echo命令的输出,发现输出的不是预期的结果。原因是$在Linux中代表一个变量,$$有特殊的作用,代表当前程序的进程ID号。这时候就需要一个反斜杠进行转义,去掉它的特殊功能,把这个extractor转义成简单的文本。[root@heimatengyuntest]#echo"thepriceis\$$PRICE"thepriceis$99案例二:将命令执行结果赋值给变量并输出[root@heimatengyuntest]#uname-aLinuxheimatengyun3.10.0-123.el7.x86_64#1SMPMonJun3012:09:22UTC2014x86_64x86_64x86_64GNU/Linux[root@heimatengyuntest]#MYSYS=`uname-a`[root@heimatengyuntest]#echo$MYSYSLinux黑马腾云3.10.0-123.el7.x86_64#1SMPMonJun3012:09:22UTC2014x86_64x86_64x86_64GNU/Linux使用uname命令查看当前操作系统信息,为变量MYSYS赋值,然后输出变量值。更多变量相关的知识会在下一篇文章中详细介绍,这里主要掌握反引号转义符。5.环境变量变量是计算机系统用来存储变量值的数据类型。在Linux系统中,变量名一般都是大写的,这是一种习惯规范。可以直接通过变量名获取对应的变量值。环境变量是一个特殊的变量,它是操作系统正常运行的前提。数百个环境变量协同工作,使操作系统能够正常为用户提供服务。但是,我们并不需要学习和掌握所有的数百个环境变量,我们只需要学习一些常用的即可。5.1env命令查看环境变量一般通过env命令查看环境变量名[root@heimatengyuntest]#envXDG_SESSION_ID=2HOSTNAME=heimatengyunSELINUX_ROLE_REQUESTED=TERM=linuxSHELL=/bin/bash...省略部分内容使用echo命令查询环境变量值[root@heimatengyuntest]#echo$SHELL/bin/bashLinux作为一个多用户多任务的操作系统,可以为每个用户提供一个独立的工作环境。因此,同一个变量会根据用户的身份不同而有不同的值。案例:使用不同用户查看HOME环境变量的值[root@heimatengyun~]#echo$HOME/root[root@heimatengyun~]#su-testLastlogin:SatNov3022:39:50CSTonpts/0[test@heimatengyun~]$echo$HOME/home/test[test@heimatengyun~]$exitlogout[root@heimatengyun~]#情况下,先用root用户查看$HOME的值,然后切换到测试用户再次查看$HOME。从测试结果来看,同样的环境变量取值是不一样的。注意:关于用户切换命令su的用法,sutest和su-test有很大区别。如果不加-,表示只切换用户,不切换shell环境。如果加上-,表示连同shell环境一起替换。这里无论是否切换shell环境,两个不同用户的$HOME值是不同的。5.2设置环境变量的导出命令变量注册由两部分组成:固定的变量名和用户或系统设置的变量值,所以我们可以根据工作需要自行创建变量。下面的例子演示了创建一个名为$MYDIR,值为/etc/profile.d/目录的自定义变量,这样我们就可以很方便的通过这个变量进入到该值对应的目录。[root@heimatengyuntest]#MYDIR=/etc/profile.d/[root@heimatengyuntest]#echo$MYDIR/etc/profile.d/[root@heimatengyuntest]#pwd/root/test[root@heimatengyuntest]#cd$MYDIR[root@heimatengyunprofile.d]#pwd/etc/profile.d此时创建的变量$MYDIR不是全局的,作用范围有限。默认情况下,它不能被其他用户使用。[root@heimatengyun~]#sutest[test@heimatengyunroot]$echo$MYDIR[test@heimatengyunroot]$exexit可以看到切换到test用户后,变量没有值,env命令也没有找到了变量。如果你想让这个变量对其他用户可用,你需要使用导出命令将它提升为一个全局变量。请注意,在导出命令后,$不会添加到变量名称中。[root@heimatengyun~]#exportMYDIR[root@heimatengyun~]#envXDG_SESSION_ID=2HOSTNAME=heimatengyunSELINUX_USE_CURRENT_RANGE=MYDIR=/etc/profile.d/...省略一些内容也可以通过env命令找到,此时我们切换到test用户看看能不能使用[root@heimatengyun~]#sutest[test@heimatengyunroot]$echo$MYDIR/etc/profile.d/[test@heimatengyunroot]$exitexit注意:再次sutest和su-test有很大区别。如果不加-,表示只是切换用户,不切换shell环境。本例只切换用户test,不切换环境,所以可以使用$MYDIR。如果使用su-test替换shell环境,则不能使用自定义的$MYDIR环境变量。5.3常用环境变量下表列出了几个重要且常用的环境变量。变量名函数HOME用户主目录SHELL用户shell解释器名HISTSIZE输出历史命令记录HISTFILESIZE保存的历史命令记录数LANG系统语言语言名PATH定义解释器搜索用户执行命令的路径5.4命令执行过程EverythinginaLinux系统就是一个文件,Linux命令也不例外。当用户执行命令时,Linux系统会发生什么?简单来说,Linux中命令的执行分为以下四个步骤(1)判断用户输入的命令是绝对路径还是相对路径,如果是则直接执行,如果不是则继续第二步(2)检查用户输入的命令是否有别名命令,如果有别名则查找原来的命令,如果没有则转第三步(3)bash解释器判断用户输入的是否为内部命令命令或外部命令,如果是内部命令则直接执行,执行外部命令第四步(4)系统在PATH环境变量中查找用户输入的命令,并执行找到文件后的命令。简单理解就是用户通过shell输入命令,shell解释器查找对应的命令文件并执行该命令。注:想一个经典的问题,当前目录(.)可以加到环境变量PATH中吗?虽然可以将当前目录(.)加入到PATH变量中,这样在某些情况下可以免去用户输入命令路径的麻烦,但这种方式存在很大的安全隐患。如果黑客在常用的公共目录/tmp下存放了一个与ls或cd同名的病毒文件,而用户恰好在公共目录下执行这些命令,就很有可能上当受骗。了解了linux命令执行过程后,当你接管一个Linux系统时,在执行命令之前先检查一下PATH变量中是否有合适的目录是个好习惯。至此,linux的大部分命令都学会了,知识积累也差不多了。在下一篇文章中,我们将综合之前所学的知识,正式进入shell编程。