前面文章咱们学习了linux基础命令,若是将不一样命令组合使用则能够成倍提升工做效率。本文将学习重定向、管道符、通配符、转义符、以及重要的环境变量相关知识,为后面的shell编程打下基础。java
前文咱们已经讲解了近60个linux经常使用命令,前文讲解的查看当前目录下有哪些文件的ls命令linux
[root@heimatengyun test]# ls test1.txt test2.txt
执行命令后默认结果是输出到电脑屏幕(显示器)上的,可是若是咱们想让命令执行结果保存到文件中,方便之后须要的时候能够随时查阅,咱们该怎么作呢?这就要用到重定向的知识。shell
Linux shell重定向是指修改系统命令的默认执行方式,咱们能够理解为“改变输入和输出的方向”,分为输入重定向和输出重定向。编程
既然重定向是改变默认的输入输出方向,那默认的输入输出方向又是什么呢?c#
相对程序而已,从键盘读取用户输入数据供程序使用,也就是数据流从键盘到程序,这就是标准的输入;程序运算产生的结果数据直接呈如今显示器上,也就是数据流从程序到显示器,这就是标准的输出。默认的标准输入、输出以下图:安全
将默认的从键盘读取数据改成从文件读取数据,也就是数据流从文件到程序,就是输入重定向;程序运算产生的结果数据不显示在显示器上而是改成输入到文件,也就是数据流从程序到文件,就是输出重定向。bash
计算机的硬件设备有不少,常见的输入设备有键盘、鼠标、麦克风、手写板等,输出设备有显示器、投影仪、打印机等。 不过,在Linux中,标准输入设备通常指键盘,标准输出设备通常指显示器。网络
前文提到过,Linux中一切皆文件,包括键盘、显示器等输入输出设备在内的全部计算机硬件都是文件。为了表示和区分已经打开的文件,Linux会为每一个文件分配一个ID,这个ID是一个整数,被称为文件描述符(File Descriptor)。学习
与输入输出有关的文件描述符以下表:操作系统
文件描述符 | 文件名 | 类型 | 硬件 |
---|---|---|---|
0 | stdin | 标准输入文件 | 硬盘 |
1 | stdout | 标准输出文件 | 显示器 |
2 | stderr | 标准错误输出文件 | 显示器 |
Linux程序在执行任何形式的IO操做时,都是在读取或写入一个文件描述符。一个文件描述符只是一个和打开的文件相关联的整数,它被扣多是一个硬盘上的普通文件、FIFO、管道、终端、键盘、显示器,甚至是一个网络链接。stdin、stdout、stderr默认都是打开的,在重定向的过程当中,0、一、2这三个文件描述符能够直接使用。
重定向分为输入和输出重定向。简言之,输入重定向就是把文件导入到命令,输出重定向则是把本来要输出到屏幕的信息写入到指定文件中。平时工做中,相对于输入重定向,输出重定向使用频率更高,所以又将输出重定向细分为标准输出重定向和错误输出重定向,输出重定向又分为:清空写入和追加两种模式。
关于标准输出和错误输出请看下面示例:
[root@heimatengyun ~]# ls test/ test1.txt test2.txt [root@heimatengyun ~]# ls xxx ls: cannot access xxx: No such file or directory
用ls命令查看制定目录下的文件信息,若是文件夹存在且文件夹下有内容将输出文件全部者、所属组、文件大小等信息,也就是ls命令的标准输出信息。可是若是查看一个不存在的文件夹,则提示文件不存在的报错信息,也就是ls命令的错误输出信息。若是要把上边本来输出到屏幕的信息直接写入到文件中而不是显示到屏幕,就要区别对待这两种输出信息。
输入重定向相关的符号和做用以下表
符号 | 做用 |
---|---|
命令 < 文件 | 将文件做为命令的标准输入 |
命令 << 分界符 | 从标准输入中读入,直到遇到分解符才中止 |
命令 < 文件1 > 文件2 | 将文件1做为命令的标准输入并将标准输出到文件2 |
输入重定向相对来讲用的不多,输入重定向的做用是将文件直接导入到命令中。/etc/passwd文件存储了系统用户信息,一行记录一个用户。如下示例演示经过输入重定向将此文件导入到wc命令,统计用户个数。
[root@heimatengyun test]# wc -l < /etc/passwd 39
输出重定向用到的符号和做用以下表
符号 | 做用 |
---|---|
命令 1> 文件 | 将标准输出重定向到文件中(清空原有文件数据),1能够省略 |
命令 2> 文件 | 将错误输出重定向到文件中(清空原有文件数据) |
命令 1>> 文件 | 将标准输出重定向到文件中(追加到原有内容后面),1能够省略 |
命令 2>> 文件 | 将错误输出重定向到文件中(追加到原有内容后面) |
命令 &>> 文件 | 将标准输出和错误输出共同写入到文件中(追加到原有内容后面) |
命令 >> 文件 2>&1 | 同上条命令:命令 &>> 文件 |
对于重定向中的标准输出模式,通常省略文件描述符1不写,而错误输出模式的文件描述符2是必需要写的。
经过man命令查看ls命令的使用方法,并将输出信息重定向到ls.txt文件中,而后就可使用cat命令查看ls.txt文件的信息。
[root@heimatengyun test]# ls test1.txt test2.txt [root@heimatengyun test]# man ls > ls.txt [root@heimatengyun test]# ls ls.txt test1.txt test2.txt [root@heimatengyun test]# cat ls.txt LS(1) User Commands LS(1) NAME ls - list directory contents SYNOPSIS ls [OPTION]... [FILE]... DESCRIPTION ...省略部份内容
接下来咱们演示清空写入和追加写入的区别,先经过覆盖写入模式向ls.txt文件(本来有ls的帮助信息内容)写入一行数据,查看内容变化,而后再经过追加写入模式向文件写入一次数据,再查看文件内容的变化
[root@heimatengyun test]# echo "wellcome" > ls.txt [root@heimatengyun test]# cat ls.txt wellcome [root@heimatengyun test]# echo "write message again" >> ls.txt [root@heimatengyun test]# cat ls.txt wellcome write message again
能够看到覆盖模式将清空文件原有内容,追加模式则在原有内容后面添加数据。
虽然都是重定向技术,不一样命令的标准输出和错误输出仍是有区别的。若是一个命令执行成功,经过标准输出到文件是没有问题的,可是若是要错误输出重定向到文件是不会成功的,依旧会显示信息到屏幕。反之,若是一个命令执行失败,经过错误输出到文件是没有问题的,可是若是要输出到标准输出是不会成功的,依旧会显示到屏幕。
经过ls命令查看一个已经存在的文件,并将信息重定向到ls.txt文件,查看该文件能够看到成功存入信息。将其错误输出重定向到ls-err.txt文件,因为查看的该文件存在,没有错误信息因此看到查询成功的文件信息依然显示在了屏幕上,而错误重定向的文件里没有内容。
[root@heimatengyun test]# ls test1.txt test2.txt [root@heimatengyun test]# ls -l test1.txt -rw-r--r--. 1 root root 0 Nov 30 15:34 test1.txt [root@heimatengyun test]# ls -l test1.txt > ls.txt [root@heimatengyun test]# ls ls.txt test1.txt test2.txt [root@heimatengyun test]# cat ls.txt -rw-r--r--. 1 root root 0 Nov 30 15:34 test1.txt [root@heimatengyun test]# ls -l test1.txt 2> ls-err.txt -rw-r--r--. 1 root root 0 Nov 30 15:34 test1.txt [root@heimatengyun test]# ls ls-err.txt ls.txt test1.txt test2.txt [root@heimatengyun test]# cat ls-err.txt
经过管道符能够把不少命令组合起来,提升工做效率。简言之管道符的做用就是:把前一个命令本来要输出到屏幕的标准正常数据看成后一个命令的标准输入。
管道符用|表示,使用格式为:命令A|命令B|命令C...
[root@heimatengyun test]# grep "/sbin/nologin" /etc/passwd |wc -l 34
经过“linux入门系列5--新手必会的linux命令”介绍的grep命令匹配/etc/passwd文件中的关键字“/sbin/nologin”查找出被限制登录系统的用户,并将匹配结果输入到wc命令,统计匹配到的行数,即为被限制登录系统的用户数。
[root@heimatengyun test]# cat test1.txt wellcome [root@heimatengyun test]# cat test1.txt |tr [a-z] [A-Z] WELLCOME [root@heimatengyun test]# cat test1.txt wellcome
经过cat命令读取test1.txt文件内容并导入到tr命令,经过tr命令将内容中的小写字母替换为大写字母。能够看到只是对读取后的内容进行替换,对原文件没有影响。
tr命令做用是替换文本文件中的字符,格式为:tr [原始字符] [目标字符]
不少时候想要快速地替换文本中的一些词汇,若是手工替换,不免工做量巨大,尤为是须要处理大批量内容的时候。这时tr命令就能够派上用场,经过管道符将文本内容传递给它进行替换操做便可。
> ps:前文讲了近60个Linux命令,命令太多不可能一一涵盖,其他的命令将根据场景需求逐步以案例的形式分散到各文中进行演示。
通配符的概念在不少语言中都存在,好比java、c#等,其做用就是模糊匹配。
假设你在电脑上存放了不少小电影,某一天忽然想看某位老师的电影做品,可是因为文件太多以致于记不清楚电影文件的名称了,只是依稀记得文件名包含了几个关键字,这时候你怎么快速找到对应的文件呢?
通配符就是面对这种场景而生,熟练使用通配符,再多电影都不迷路。通配符顾名思义就是通用的匹配信息的符号,主要包含如下几个:
符号 | 意义 |
---|---|
* | 匹配0个和多个字符 |
? | 匹配单个字符 |
[0-9] | 匹配0~9之间的单个数字字符 |
[123] | 匹配一、二、3这三个指定数字中的任意一个数字 |
[abc] | 匹配a、b、c三个字符中的任意一个字符 |
[root@heimatengyun test]# ls test1.txt test2.txt [root@heimatengyun test]# ls -l test* -rw-r--r--. 1 root root 9 Nov 30 20:43 test1.txt -rw-r--r--. 1 root root 0 Nov 30 15:34 test2.txt
[root@heimatengyun test]# ls test1.txt test2.txt [root@heimatengyun test]# ls -l test[13].txt -rw-r--r--. 1 root root 9 Nov 30 20:43 test1.txt
“linux入门系列5--新手必会的linux命令”提到,人和Linux内核之间的交互是经过在shell终端中执行相关命令来实现的,为了能更好地理解用户的表达,除了通配符、管道符,shell解释器还提供了特别丰富的转义字符来处理用户输入的特殊数据。
本文只抽取几个经常使用的通配符进行讲解,转义符及对应的功能以下:
转义符 | 做用 |
---|---|
\ | 反斜杠,使后边的一个变量变为单纯的字符串 |
'' | 单引号,转义其中全部的变量为单纯的字符串 |
"" | 双引号,保留其中的变量属性,不进行转义处理 |
`` | 反引号,把其中的命令执行后返回结果 |
[root@heimatengyun test]# PRICE=99 [root@heimatengyun test]# echo "the price is $PRICE" the price is 99 [root@heimatengyun test]# echo "the price is $$PRICE" the price is 12395PRICE
定义PRICE变量保存价格,而后经过echo命令输出,发现输出的不是预期结果。缘由是Linux中$表示变量,$$则有特殊的做用,表示当前程序的进程ID号。这时就须要反斜杠来进行转义,去除其特殊功能,将这个提取符转义为单纯的文本。
[root@heimatengyun test]# echo "the price is \$$PRICE" the price is $99
[root@heimatengyun test]# uname -a Linux heimatengyun 3.10.0-123.el7.x86_64 #1 SMP Mon Jun 30 12:09:22 UTC 2014 x86_64 x86_64 x86_64 GNU/Linux [root@heimatengyun test]# MYSYS=`uname -a` [root@heimatengyun test]# echo $MYSYS Linux heimatengyun 3.10.0-123.el7.x86_64 #1 SMP Mon Jun 30 12:09:22 UTC 2014 x86_64 x86_64 x86_64 GNU/Linux
用uname命令查看当前操做系统信息,并赋值给变量MYSYS,而后输出变量值。更多变量相关知识将在下一篇文章中详细介绍,此处主要掌握反引号这个转义符。
变量是计算机系统用于保存可变值的数据类型,在Linux系统中,变量名称通常是大写的,这是一种约定俗成的规范。直接经过变量名便可得到对应的变量值。
环境变量是一种特殊的变量,是操做系统要正常运行的前提,数百个环境变量协同工做才使得操做系统能正常为用户提供服务。然而咱们没有必要去所有学习和掌握全部数百个环境变量,只须要学习一部分经常使用的便可。
通常经过env命令查看环境变量名
[root@heimatengyun test]# env XDG_SESSION_ID=2 HOSTNAME=heimatengyun SELINUX_ROLE_REQUESTED= TERM=linux SHELL=/bin/bash ...省略部份内容
用echo命令查询环境变量值
[root@heimatengyun test]# echo $SHELL /bin/bash
Linux做为一个多用户多任务操做系统,可以为每一个用户提供独立的工做环境,所以,一个相同的变量会由于用户身份的不一样而具备不一样的值。
案例:使用不一样用户查看HOME环境变量的值
[root@heimatengyun ~]# echo $HOME /root [root@heimatengyun ~]# su - test Last login: Sat Nov 30 22:39:50 CST 2019 on pts/0 [test@heimatengyun ~]$ echo $HOME /home/test [test@heimatengyun ~]$ exit logout [root@heimatengyun ~]#
案例中先使用root用户查看$HOME的值,而后切换到test用户再次查看$HOME,从试验结果上看相同环境变量值倒是不同的。
> 注意:关于用户切换命令su的用法,su test和su - test是有很是大区别的,若是不加-表示只是切换用户不切换shell环境,若是加上-则表示连同shell环境一块儿替换,此处不管是否切换shell环境,两个不一样用户的$HOME值都不同。
变量是由固定的变量名与用户或系统设置的变量值两部分注册,所以咱们彻底能够根据工做须要自行建立变量。
如下案例演示建立一个名称为$MYDIR,值为/etc/profile.d/ 目录的自定义变量,这样咱们只须要经过该变量,就能够很方便的进入到值对应的目录。
[root@heimatengyun test]# MYDIR=/etc/profile.d/ [root@heimatengyun test]# echo $MYDIR /etc/profile.d/ [root@heimatengyun test]# pwd /root/test [root@heimatengyun test]# cd $MYDIR [root@heimatengyun profile.d]# pwd /etc/profile.d
此时建立的变量$MYDIR不具备全局性,做用范围有限,默认状况下不能被其余用户使用。
[root@heimatengyun ~]# su test [test@heimatengyun root]$ echo $MYDIR [test@heimatengyun root]$ exit exit
能够看到切换到test用户后,该变量没有值,而且经过env命令查看也未查到该变量。
若是要想让其余用户也可使用该变量,则须要用export命令,将其提高为全局变量。注意export命令后的变量名不加$。
[root@heimatengyun ~]# export MYDIR [root@heimatengyun ~]# env XDG_SESSION_ID=2 HOSTNAME=heimatengyun SELINUX_USE_CURRENT_RANGE= MYDIR=/etc/profile.d/ ...省略部份内容
经过env命令也能够查到该变量,此时咱们在切换到test用户查看是否可使用
[root@heimatengyun ~]# su test [test@heimatengyun root]$ echo $MYDIR /etc/profile.d/ [test@heimatengyun root]$ exit exit
> 注意:再次强调一下,su test和su - test是有很是大区别的,若是不加-表示只是切换用户不切换shell环境。本例只是切换用户到test并没切换环境因此可使用$MYDIR,若是使用su - test 把shell环境也替换的话,将没法使用自定义的$MYDIR环境变量。
下表列举几个重要经常使用的环境变量
变量名称 | 做用 |
---|---|
HOME | 用户家目录 |
SHELL | 用户在使用的shell解释器名称 |
HISTSIZE | 输出的历史命令记录条数 |
HISTFILESIZE | 保存的历史命令记录条数 |
LANG | 系统语言、语系名称 |
PATH | 定义解释器搜索用户执行命令的路径 |
Linux系统中一切皆文件,Linux命令也不例外。当用户执行一条命令以后,Linux系统到底发生了什么事情呢?
简单来讲,命令在Linux中的执行分为如下4个步骤
(1)判断用户是否以绝对路径或相对路径的方式输入命令,若是是则直接执行,不是则进行第二步
(2)检查用户输入的命令是否有别名命令,若是有别名找到原命令,若是无则进行第三步
(3)bash解释器判断用户输入的是内部命令仍是外部命令,如是内部命令则直接执行,外部命令则进行第四步
(4)系统在PATH环境变量中查找用户输入的命令,找到文件后执行命令。
简单理解就是用户经过shell输入命令,shell解释器查找对应的命令文件并执行命令。
> 注意:思考一下一个经典的问题,可否将当前目录(.)添加到环境变量PATH中呢? > > 尽管能够将当前目录(.)添加到PATH变量中,使得在某些状况下可让用户免去输入命令路径的麻烦,可是,这样存在很大的安全风险。假如黑客在经常使用的公用目录/tmp下存放一个与ls或cd等命令同名的病毒文件,而用户恰巧又在公共目录中执行了这些命令,那就极可能中招了。
了解linux命令执行流程后,当接手一台Linux系统后,在执行命令前先检查PATH变量中是否有能够的目录,这是一个很好的习惯。
至此,已经学习了大部分Linux命令,知识积累的差很少了,下一篇文章咱们将综合前面学到的知识,正式进入shell编程。