第3章 管道符、重定向与环境变量

章节概述:

Don't be so excited!虽然此刻您已经学完了上百个常用Linux命令,但如前面所说:“光用命令本身并不能做好工作”。

下个章节将学习Shell脚本的使用方法,所以本章节要有些承上启下的作用,理论知识点会比较多,但都很实用。

当读者学习完管道命令符输入输出重定向通配符以及环境变量后便可以将命令组合的更加恰当、高效率。

3.1 管道命令符

管道命令符“|”的作用是将前一个命令的标准输出当作是后一个命令的标准输入,格式为“命令A|命令B”。例如前面章节学习的通过grep文本搜索命令匹配关键词"/sbin/nologin"找出了所有被限制登陆系统的用户,如果我们希望再统计所有不允许登陆系统的用户个数,就可以将下面这两条命令进行结合:

找出被限制登陆用户的命令是:grep "/sbin/nologin" /etc/passwd

统计文本行数的命令则是:wc -l

现在要做的是就是将搜索命令的输出值传递给统计命令,其实只要把管道符夹在中间就可以了。

[root@linuxprobe ~]# grep "/sbin/nologin" /etc/passwd | wc -l
33
很厉害的功能吧!我们将原本将会显示到屏幕上的用户信息列表交给"wc -l"命令做了进一步的加工,简直太方便了!!

用翻页的形式查看/etc目录中有那些文件:

[root@linuxprobe ~]# ls -l /etc/ | more
total 1400
drwxr-xr-x. 3 root root 97 Jul 10 17:26 abrt
-rw-r--r--. 1 root root 16 Jul 10 17:36 adjtime
-rw-r--r--. 1 root root 1518 Jun 7 2013 aliases
-rw-r--r--. 1 root root 12288 Jul 10 09:38 aliases.db
drwxr-xr-x. 2 root root 49 Jul 10 17:26 alsa
drwxr-xr-x. 2 root root 4096 Jul 10 17:31 alternatives
-rw-------. 1 root root 541 Jan 28 2014 anacrontab
-rw-r--r--. 1 root root 55 Jan 29 2014 asound.conf
-rw-r--r--. 1 root root 1 Jan 29 2014 at.deny
drwxr-xr-x. 2 root root 31 Jul 10 17:27 at-spi2
drwxr-x---. 3 root root 41 Jul 10 17:26 audisp
drwxr-x---. 3 root root 79 Jul 10 17:37 audit
drwxr-xr-x. 4 root root 94 Jul 10 17:26 avahi
………………省略部分文件………………

向linuxprobe用户发送一封邮件:

[root@linuxprobe ~]# echo "Content" | mail -s "Subject" linuxprobe

切换至linuxprobe用户:

[root@linuxprobe ~]# su - linuxprobex
Last login: Fri Jul 10 09:44:07 CST 2015 on :0

查看邮件箱,果然有一封邮件哦:

[linuxprobe@linuxprobe ~]$ mail
Heirloom Mail version 12.5 7/5/10. Type ? for help.
"/var/spool/mail/linuxprobe": 1 message 1 new
>N 1 root Sun Aug 30 17:33 18/578 "Subject"

使用非交互式设置用户密码,将root的密码修改为linuxprobe。

[root@linuxprobe ~]# echo "linuxprobe" | passwd --stdin root
Changing password for user root.
passwd: all authentication tokens updated successfully.
当然同学们可不要误解管道命令符只能用一次哦,完全可以这样用:“命令A|命令B|命令C”。另外为了进一步方便学生去记忆、理解管道符这个东西,我在讲课的时候还会把管道符描述成“任意门”,小时候大家也一定看过哆啦a梦吧,机器猫经常为了大雄而从口袋中掏出一件件宝贝,好多次就用到了任意门这个道具,有一集大雄为了邀请朋友们来家玩,于是用任意门穿越到了火星上面,还把家里的水管放到了火星上,那么管道符就好像是数据用于穿越的任意门,帮助我们提高工作效率,完成之前不敢想象的事情。

出现问题?大胆提问!

因读者们硬件不同或操作错误都可能导致实验配置出错,请耐心再仔细看看操作步骤吧,不要气馁~

Linux技术交流请加A群:560843(),B群:340829(推荐),点此查看全国群

*本群特色:通过口令验证确保每一个群员都是《Linux就该这么学》的读者,答疑更有针对性,不定期免费领取定制礼品。

3.2 输入和输出重定向

要想通过Linux命令让数据的处理更加的高效,就特别有必要搞明白输入和输出重定向的原理,简单描述即“使用输入重定向能够将文件导入到命令中,而输出重定向则是能够将原本要输出到屏幕的信息写入到指定文件中”。在日常工作和学习中一般使用输出重定向会稍微多一些,所以细分下又有了标准输出重定向错误输出重定向两种不同的东西,讲完了理论之后,就来看下演示吧:

[root@linuxprobe ~]# ls linuxprobe/
[root@linuxprobe ~]# ls xxxxxx/
ls: cannot access xxxxxx: No such file or directory

刚刚我们先查看了一个名为linuxprobe目录内的文件,后又尝试查看名为"xxxxxx"目录内的文件,显示该目录并不存在。虽然好像命令都执行成功了,但其实有所差异,前者执行后返回的是标准输出,而后者执行失败返回的是错误输出

标准输入(STDIN,文件描述符为0):默认从键盘输入,为0时表示是从其他文件或命令的输出。

标准输出(STDOUT,文件描述符为1):默认输出到屏幕,为1时表示是文件。

错误输出(STDERR,文件描述符为2):默认输出到屏幕,为2时表示是文件。

对于输入重定向有这些情况:

编辑
符号 作用
命令 < 文件 将文件作为命令的标准输入
命令 << 分界符 从标准输入中读入,直到遇见“分界符”才停止
命令 < 文件1 > 文件2 将文件1作为命令的标准输入并将标准输出到文件2

对于输出重定向符有这些情况:

编辑
符号 作用
命令 > 文件 将标准输出重定向到一个文件中(清空原有文件的数据)
命令 2> 文件 将错误输出重定向到一个文件中(清空原有文件的数据)
命令 >> 文件 将标准输出重定向到一个文件中(追加到原有内容的后面)
命令 2>> 文件 将错误准输出重定向到一个文件中(追加到原有内容的后面)
命令 >> 文件 2>&1 或 命令 &> 文件 将标准输出与错误输出共同写入到文件中(追加到原有内容的后面)

那么来做几个输出和输入重定向的实验吧:
将man命令的帮助文档写入到readme.txt文件中:

[root@linuxprobe ~]# man bash > readme.txt

向readme.txt文件中写入一行文字:

[root@linuxprobe ~]# echo "Welcome to LinuxProbe.Com" > readme.txt

向readme.txt中追加一行文字:

[root@linuxprobe ~]# echo "Quality linux learning materials" >> readme.txt

因为刚刚我们第二次使用的是“>”清空输出重定向,因此上面的man bash命令的在文件中的输出信息会被清空后再写入新的问题,所以此时查看下readme.txt中的内容:

[root@linuxprobe ~]# cat readme.txt
Welcome to LinuxProbe.Com
Quality linux learning materials

readme.txt文件作为输入重定向给wc -l命令来计算行数,命令等同于"cat readme.txt | wc -l"

[root@linuxprobe ~]# wc -l < readme.txt
2

用echo、mail和管道符命令(|)发给linuxprobe用户一封邮件,但内容只能有一句话。

[root@linuxprobe ~]# echo "Content" | mail -s "Subject" linuxprobe

如果您想像写信一样发邮件,就用输入重定向试试吧,向指定邮箱发送一封邮件,标题为Readme,内容逐行输入。
其中的over被称为分节符,是用户自定义的,当系统遇到这个分界符时会认为输入结束。

[root@linuxprobe ~]# mail -s "Readme" root@linuxprobe.com << over
> I think linux is very practical
> I hope to learn more
> can you teach me ?
> over
正常情况下输入分界符后会结束输入操作并发送邮件,不会有报错信息。
[root@linuxprobe ~]#

这次咱们还是用"ls"命令查看文件信息,若文件不存在则将报错信息输出到/root/stderr.txt中:

[root@linuxprobe ~]# ls linuxprobe 2> /root/stderr.txt
-rw-r--r--. 1 root root 0 Mar  1 13:30 linuxprobe

文件为空,代表上面命令并没有报错:

[root@linuxprobe ~]# cat /root/stderr.txt

将查看xxxxxx目录命令的错误信息输出到/root/stderr.txt文件中:

[root@linuxprobe ~]# ls xxxxxx 2> /root/stderr.txt

查看到stderr.txt文件中保存的ls命令报错信息:

[root@linuxprobe ~]# cat /root/stderr.txt
ls: cannot access xxxxxx: No such file or directory

因为"linuxprobe"的文件确实存在,所有没有报错信息,但"xxxxxx"文件是不存在的,所以则将报错信息输出到了指定的文件。

3.3 命令行通配符

文件名应该是日常命令中最常常用到的参数对象吧,但是有些时候真的就想不起来全名,于是我们可以通过匹配一部分的文件名字后进行通配符的搜索,例如想要批量查看硬盘文件属性,那么正常命令会是:

[root@linuxprobe ~]# ls /dev/sda
[root@linuxprobe ~]# ls /dev/sda1
[root@linuxprobe ~]# ls /dev/sda2
[root@linuxprobe ~]# ls /dev/sda3

但此时如果不知道分区的个数或分区号,这时候就要用到通配符来搞定了,Bash解释器的支持多种文本通配符包括:

编辑
通配符 含义
* 匹配零个或多个字符。
? 匹配任意单个字符。
[0-9] 匹配范围内的数字。
[abc] 匹配已出的任意字符。

查看sda开头的所有设备文件:

[root@linuxprobe ~]# ls /dev/sda*
/dev/sda /dev/sda1 /dev/sda2

查看sda后面有一个字符的设备文件:

[root@linuxprobe ~]# ls /dev/sda?
/dev/sda1 /dev/sda2

查看sda后面包含0-9数字的设备文件:

[root@linuxprobe ~]# ls /dev/sda[0-9]
/dev/sda1 /dev/sda2

查看sda后面是1或3或5的设备文件:

[root@linuxprobe ~]# ls /dev/sda[135]
/dev/sda1

另外bash解释器还支持很多的特殊字符扩展:

编辑
字符 作用
(反斜杠) 转义后面单个字符
''(单引号) 转义所有的字符
""(双引号) 变量依然生效
``(反引号) 执行命令语句

定义名称为PRICE的变量值为5:

[root@linuxprobe ~]# PRICE=5

想要输出"价格是5":

[root@linuxprobe ~]# echo "Price is $PRICE"
Price is 5

想要输出"价格是$5",但因为美元符号与代表变量取值的$符号冲突了,所以报错了:

[root@linuxprobe ~]# echo "Price is $$PRICE"
Price is 3767PRICE

添加一个反斜杠,将第一个$符号转义:

[root@linuxprobe ~]# echo "Price is $$PRICE"
Price is $5

使用单引号,变量将不再被取值:

[root@linuxprobe ~]# echo 'Price is $$PRICE'
Price is $$PRICE

执行uname -a后可以查看到本机内核的版本与架构信息(反引号里面的命令会被执行):

[root@linuxprobe ~]# echo `uname -a`
Linux linuxprobe.com 3.10.0-123.el7.x86_64 #1 SMP Mon May 5 11:16:57 EDT 2014 x86_64 x86_64 x86_64 GNU/Linux
3.4 实用的PATH变量
alias命令用于设置命令的别名,格式为:“alias 别名=命令”。
例如担心复制文件时误将文件覆盖,那么执行alias cp="cp -i"则每次覆盖都会询问用户。
unalias命令用于取消命令的别名,格式为:“unalias 别名”。

设置cp命令的别名:

[root@linuxprobe ~]# alias cp="cp -i"

取消cp命令的别名:

[root@linuxprobe ~]# unalias cp
如同前面所讲的——在Linux中所有的一切都是文件,命令文件也不例外。那当用户执行了一条"ls"命令后发生了什么事情?
步骤一:如果是以绝对/相对路径输入的命令则直接执行(如执行/bin/ls)。
步骤二:检查是否为alias别名命令。
步骤三:由bash判断其是“内部命令”还是“外部命令”。
内部命令:属于解释器内部的
外部命令:独立于解释器外的命令文件
步骤四:通过$PATH变量中定义的路径进行命令查找。
查看$PATH变量的方法:echo $PATH
/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin:/bin:/sbin
如果您想知道某个命令是“内部命令”还是“外部命令”?执行执行“type 命令名字”,解释器就会告诉你呦~
$PATH变量是“解释器的助手”,它负责告诉bash用户要执行的命令可能存放在那里,然后bash就会乖乖的在这些目录里寻找。
在变量$PATH中目录之间用冒号“:”间隔开了,当然您也能自定义一些命令存放目录,比如/root/bin。

查看当前的$PATH变量内容:

[root@linuxprobe ~]# echo $PATH
/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin:/bin:/sbin

为变量增加新的值:

[root@linuxprobe ~]# PATH=$PATH:/root/bin

查看此时的$PATH变量内容:

[root@linuxprobe ~]# echo $PATH
/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin:/bin:/sbin:/root/bin
这里有比较经典的问题:“为什么不能在$PATH中添加进当前目录(.)那?”仔细想想再看答案(答案模式)!
答案:虽然将$PATH变量添加了当前目录(.)会在一些情况让用户免去输入命令所在路径的麻烦,但如果黑客在比较常用的公共目录/tmp中存放了一个名为"ls"或"cd"的同名木马文件,那么用户就极有可能错误的执行了。
谨慎而有经验的运维人员在接手一台Linux系统后一定会在执行命令前查看下$PATH变量中是否有可疑的目录。
3.5 重要的环境变量
上面学到的$PATH是不是很实用?在Linux系统中还有许多重要的环境变量,我们可以用env命令查看到它们。
变量是由固定的“变量名”与用户或系统设置的“变量值”两部分组成的,如果有需求可直接修改~
编辑
变量名称 作用
HOME 用户的主目录“家”。
SHELL 当前的shell是哪个程序
HISTSIZE 历史命令记录条数
MAIL 邮件信箱文件
LANG 语系数据
RANDOM 随机数字
PS1 bash提示符
HISTFILESIZE history命令存储数量
PATH 在路径中的目录查找执行文件
EDITOR 默认文本编辑器
让我们通过变量来查看下当前用户的家目录是哪个吧。

因为当前是以root用户登陆,所以显示为/root:

[root@linuxprobe ~]# echo $HOME
/root

切换到linuxprobe用户:

[root@linuxprobe ~]# su - linuxprobe
Last login: Fri Feb 27 19:49:57 CST 2015 on pts/0

切换为linuxprobe用户后,同样的"$HOME"变量却显示出了不同的值:

[linuxprobe@linuxprobe ~]$ echo $HOME
/home/linuxprobe
假设需要设置一个变量"WORKDIR",让每个用户执行"cd $WORKDIR"都登陆到/home/workdir目录中,该如何做那?
定义方法:变量名称=新的值
查看方法:echo $变量名称

创建该目录:

[root@linuxprobe ~]# mkdir /home/workdir

如前面所介绍的方法设置变量:

[root@linuxprobe ~]# WORKDIR=/home/workdir

成功切换,好棒!

[root@linuxprobe ~]# cd $WORKDIR
[root@linuxprobe workdir]# pwd
/home/workdir

切换到linuxprobe用户:

[root@linuxprobe workdir]# su linuxprobe
Last login: Fri Mar 20 20:52:10 CST 2015 on pts/0

好奇怪,为什么没有切换到/home/workdir目录呢:

[linuxprobe@linuxprobe ~]$ cd $WORKDIR

用echo查看发现该变量为空值:

[linuxprobe@linuxprobe ~]$ echo $WORKDIR
现在的问题是为什么某个用户设置的环境变量不能被其他用户使用?原因就在于变量的作用范围。
export命令用于将局部变量提升为全局变量,格式为:“export 变量名[=变量值]”。

将WORKDIR变量设置为全局变量:

[root@linuxprobe ~]# export WORKDIR

切换为linuxprobe用户:

[root@linuxprobe workdir]# su linuxprobe
Last login: Fri Mar 20 21:52:10 CST 2015 on pts/0

很棒哦~成功的切换了目录:

[linuxprobe@linuxprobe ~]$ cd $WORKDIR
[linuxprobe@linuxprobe workdir]$pwd
/home/workdir
原文地址:https://www.cnblogs.com/linux130/p/5726363.html