这个系列的Linux教程主要参考刘遄老师的《Linux就该这么学》。用的系统是RHEL8,如果遇见一些命令出现问题,请首先检查自己的系统是否一致,如果不一致,可网上查一下系统间某些命令之间的差异。
目前设计的这个Linux学习系列的目录如下:(会陆续更新~)
- Linux 学习系列一:Linux的简单介绍以及命令行的基本操作
- Linux 学习系列二:Linux中的常用命令
- Linux 学习系列三:管道符、重定向与环境变量
- Linux 学习系列四:光速掌握Vim,效率提升神器
- Linux 学习系列五:Shell命令脚本的基本语法
- Linux 学习系列六:用户身份与文件权限
- …
\quad
\quad
管道符、重定向与环境变量
输入输出重定向
输入重定向是指把文件导入到命令中,而输出重定向则是指把原本要输出到屏幕的数据信息写入到指定文件中。
- 标准输入重定向(STDIN,文件描述符为 0):默认从键盘输入,也可从其他文件或命令中输入。
- 标准输出重定向(STDOUT,文件描述符为 1):默认输出到屏幕。
- 错误输出重定向(STDERR,文件描述符为 2):默认输出到屏幕。
首先,需要知道什么是标准输出,什么是错误输出。一个命令如果报错就是错误输出。
[lucky@wz ~]$ ls -l haha.sh
-rw-rw-r--. 1 lucky lucky 46 Feb 24 21:53 haha.sh
[lucky@wz ~]$ ls -l jdpocpsodjgpo
ls: cannot access 'jdpocpsodjgpo': No such file or directory
上述命令种,haha.sh
是存在的,所以其输出信息是该文件的一些相关权限,所有者等信息,这就是标准输出信息。而第二个文件是不存在的,所以显示的是该命令的错误输出信息。如果要将原本输出到屏幕上的数据转而写入到文件当中,就要区别对待这两种输出信息。
下面列举一下输入重定向和输出重定向常用的符号及其作用:
- 输入重定向中用到的符号及其作用
符号 | 作用 |
---|---|
命令 < 文件 | 将文件作为命令的标准输入 |
命令 << 分界符 | 从标准输入中读入,直到遇见分界符才停止 |
命令 < 文件 1 > 文件 2 | 将文件 1 作为命令的标准输入并将标准输出到文件 2 |
- 输出重定向中用到的符号及其作用
符号 | 作用 |
---|---|
命令 > 文件 | 将标准输出重定向到一个文件中(清空原有文件的数据) |
命令 2> 文件 | 将错误输出重定向到一个文件中(清空原有文件的数据) |
命令 >> 文件 | 将标准输出重定向到一个文件中(追加到原有内容的后面) |
命令 2>> 文件 | 将错误输出重定向到一个文件中(追加到原有内容的后面) |
命令 >> 文件 2>&1 或命令 &>> 文件 | 将标准输出与错误输出共同写入到文件中 |
(追加到原有内容的后面) |
注意:
- 对于重定向中的标准输出模式,可以省略文件描述符 1 不写,而错误输出模式的文件描述符 2 是必须要写的。
- 上面的
>
与>>
符号的区别类似写入文件时,指定的文件打开方式w
和a
。
下面列举一些例子,来说明一下重定向的用法:
- 标准输出重定向到一个文件中(覆盖写入)
[root@wz lucky]# ll > readme.txt
[root@wz lucky]# cat readme.txt
total 20
drwxr-xr-x. 2 lucky lucky 6 Jan 18 11:18 Desktop
drwxr-xr-x. 2 lucky lucky 6 Jan 18 11:18 Documents
drwxr-xr-x. 2 lucky lucky 6 Jan 18 11:18 Downloads
drwxrwxr-x. 3 lucky lucky 18 Jun 9 07:47 gaga
-rw-rw-r--. 1 lucky lucky 53 Feb 22 06:32 haha
-rw-rw-r--. 1 lucky lucky 46 Feb 24 21:53 haha.sh
-rw-rw-r--. 1 lucky lucky 55 Feb 22 06:37 hoho
drwxr-xr-x. 2 lucky lucky 6 Jan 18 11:18 Music
-rw-rw-r--. 1 lucky lucky 535 Jan 19 09:47 oeasy.txt
-rw-rw-r--. 1 lucky lucky 15 Feb 25 02:36 passwd.txt
drwxr-xr-x. 2 lucky lucky 6 Jan 18 11:18 Pictures
drwxr-xr-x. 2 lucky lucky 6 Jan 18 11:18 Public
-rw-r--r--. 1 root root 0 Jun 9 21:17 readme.txt
drwxr-xr-x. 2 lucky lucky 6 Jan 18 11:18 Templates
drwxr-xr-x. 2 lucky lucky 6 Jan 18 11:18 Videos
[root@wz lucky]# ls -l readme.txt > readme.txt
[root@wz lucky]# cat readme.txt
-rw-r--r--. 1 root root 0 Jun 9 21:19 readme.txt
命令 > 文件
会清空文件再写入。
- 标准输出重定向到一个文件中(追加写入)
[root@wz lucky]# echo "aoaoaoaoao" >> readme.txt
[root@wz lucky]# cat readme.txt
-rw-r--r--. 1 root root 0 Jun 9 21:19 readme.txt
aoaoaoaoao
- 虽然都是输出重定向技术,但是不同命令的标准输出和错误输出还是有区别。 如果想把命令的报错信息写入到文件,该怎么操作呢?当用户在执行一个自动化的 Shell 脚本时,这个操作会特别有用,而且特别实用,因为它可以把整个脚本执行过程中的报错信息都记录到文件中,便于安装后的排错工作。
[root@wz lucky]# ls -l xxx
ls: cannot access 'xxx': No such file or directory
[root@wz lucky]# ls -l xxx 2> readme.txt
[root@wz lucky]# cat readme.txt
ls: cannot access 'xxx': No such file or directory
- 输入重定向的作用是把文件直接导入到命令中。接下来使用输入重定向把
readme.txt
文件导入给wc -l
命令,统计一下文件中的内容行数。
[root@wz lucky]# wc -l < readme.txt
1
上述命令实际上等同于cat readme.txt | wc -l
的管道符命令组合。 接下来就来讲一下管道符命令。
管道命令符
管道符的执行格式为“命令A | 命令B
”。命令符的作用可以用一句话来概括“把前一个命令原本要输出到屏幕的数据当作是后一个命令的标准输入”。
举一些例子:
- 统计被限制登录系统的用户个数: 通过
grep
文本搜索命令匹配关键词/sbin/nologin
找出了所有被限制登录系统的用户,然后将其输入到统计文本行数的命令中,wc -l
统计行数。
[root@wz lucky]# grep "sbin/nologin" /etc/passwd | wc -l
40
- 在修改用户密码时,通常都需要输入两次密码以进行确认,这在编写自动化脚本时将成为一个非常致命的缺陷。通过把管道符和
passwd
命令的--stdin
参数相结合,我们可以用一条命令来完成密码重置操作:
[root@wz lucky]# echo "gaga" | passwd --stdin root
Changing password for user root.
passwd: all authentication tokens updated successfully.
此外,管道命令符在一个命令组合中可以使用多次,我们完全可以这样使用:“命令A | 命令B | 命令C
”。
命令行的通配符
通配符就是通用的匹配信息的符号,比如:
- 星号(
*
)代表匹配零个或多个字符; - 问号(
?
)代表匹配单个字符; - 中括号
[]
匹配指定范围内的任意单个字符,有多种特殊格式,见下表: - 中括号内加上数字
[0-9]
代表匹配 0~9 之间的单个数字的字符; - 中括号内加上字母
[abc]
则是代表匹配a
、b
、c
三个字符中的任意一个字符。
另外,下面列出一些常简的符号:
符号 | 作用 |
---|---|
[a-z],[A-Z] | 不区分大小写,表示a~z 中的任意一个字母 |
[0-9] | 0~9任意一个数字 |
[a-z0-9] | 任意一个字母或任意一个数字 |
[[:upper:]] | 所有大写字母 |
[[:lower:]] | 所有小写字母 |
[[:alpha:]] | 所有字母 |
[[:digit:]] | 所有数字 |
[[:alnum:]] | 所有的字母和数字 |
[[:space:]] | 所有空白字符 |
[[:punct:]] | 所有标点符号 |
[^] | 匹配指定范围外的任意单个字符。如非大写字母外的所有字符[^[:upper:]] ,非数字[^[0-9]] |
例子:
[root@wz dev]# ls tty*
tty tty12 tty17 tty21 tty26 tty30 tty35 tty4 tty44 tty49 tty53 tty58 tty62 ttyS0
tty0 tty13 tty18 tty22 tty27 tty31 tty36 tty40 tty45 tty5 tty54 tty59 tty63 ttyS1
tty1 tty14 tty19 tty23 tty28 tty32 tty37 tty41 tty46 tty50 tty55 tty6 tty7 ttyS2
tty10 tty15 tty2 tty24 tty29 tty33 tty38 tty42 tty47 tty51 tty56 tty60 tty8 ttyS3
tty11 tty16 tty20 tty25 tty3 tty34 tty39 tty43 tty48 tty52 tty57 tty61 tty9
[root@wz dev]# ls tty?
tty0 tty1 tty2 tty3 tty4 tty5 tty6 tty7 tty8 tty9
[root@wz dev]# ls tty[0-9]
tty0 tty1 tty2 tty3 tty4 tty5 tty6 tty7 tty8 tty9
注意,看下面的代码:
[root@wz dev]# ls tty[1,3,5,20]
tty0 tty1 tty2 tty3 tty5
注意:[1,3,5,20]
匹配不出20,只会匹配出2和0!所以其实上面的,
可以省略,不过为了避免混淆,尽量写上。
一些练习的题目:
- 显示
/var
目录下所有以l
开头,以一个小写字母结束,且中间出现一位任意字符的文件或目录:
ls -d /var/log/l?[[:lower:]]
- 显示
/etc
目录下。以任意一位数字开头,且以非数字结尾的文件或目录:
ls -d /etc/[0-9]*[^0-9]
- 显示
/etc
目录下,以非字母开头,后面跟一个字母及其他任意长度任意字符的文件或目录:
ls -d /etc/[^[a-z]][a-z]*
- 复制
/etc
目录下,所有以m
开头,以非数字结尾的文件或目录至/tmp/m
目录:
cp -r /etc/m*[^[0-9]] /etc/m/
- 复制
/usr/share/man
目录下,所有以man
开头,后跟一个数字结尾的文件或目录到/tmp/man
目录:
cp -r /usr/share/man/man[0-9] /tmp/man/
- 复制
/etc
目录下,所有以.conf
结尾,且以m,n,r,p
开头的文件或目录到/tmp/conf.d
目录下:
cp -r /etc/[mnrp]*.conf /etc/conf.d/
常用的转义字符
4 个最常用的转义字符如下所示。
- 反斜杠(
\
):使反斜杠后面的一个变量变为单纯的字符串。 - 单引号(
''
):转义其中所有的变量为单纯的字符串。 - 双引号(
""
):保留其中的变量属性,不进行转义处理。 - 反引号(````):把其中的命令执行后返回结果。
例子: 先定义一个名为 PRICE
的变量并赋值为 5,然后输出以双引号括起来的字符串与变量信息:
[root@wz dev]# PRICE=5
[root@wz dev]# echo "Price is $PRICE"
Price is 5
注意,和类似Python这类语言不一样的是,不能写成
PRICE = 5
,也就是说不能有空格!
我们希望能够输出“Price is $5
”,但碰巧美元符号与变量提取符号合并后的$$
作用是显示当前程序的进程ID号码。
[root@wz dev]# echo "Price is $$PRICE"
Price is 9524PRICE
这并不是我们想要的结果,如果想要显示$
,可以使用反斜杠进行转义,去除其特殊功能。
t@wz dev]# echo "Price is \$PRICE"
Price is $PRICE
也可以直接使用单引号括起来,因为单引号会转义其中所有的变量为单纯的字符串。
[root@wz dev]# echo 'Price is $PRICE'
Price is $PRICE
如果只需要某个命令的输出值时,可以像命令
这样,将命令用反引号括起来,达到预期的效果。例如,将反引号与uname -a
命令结合,然后使用echo
命令来查看本机的 Linux 版本和内核信息:
[root@wz dev]# echo `uname -a`
Linux wz 4.18.0-80.el8.x86_64 #1 SMP Wed Mar 13 12:02:46 UTC 2019 x86_64 x86_64 x86_64 GNU/Linux
重要的环境变量
变量是计算机系统用于保存可变值的数据类型。在 Linux 系统中,变量名称一般都是大写的,这是一种约定俗成的规范。
简单来说,命令在 Linux 中的执行分为 4 个步骤。
- 判断用户是否以绝对路径或相对路径的方式输入命令(如
/bin/ls
),如果是的话则直接执行。 - Linux 系统检查用户输入的命令是否为“别名命令”,即用一个自定义的命令名称来替换原本的命令名称。
- Bash 解释器判断用户输入的是内部命令还是外部命令。内部命令是解释器内部的指令,会被直接执行;而用户在绝大部分时间输入的是外部命令,这些命令交由步骤4继续处理。
- 系统在多个路径中查找用户输入的命令文件,而定义这些路径的变量叫作
PATH
,作用是告诉 Bash 解释器待执行的命令可能存放的位置,然后 Bash 解释器就会乖乖地在这些位置中逐个查找。
** 别名命令**:在使用rm
命令删除文件时,Linux 系统都会要求我们再确认是否执行删除操作, 其实这就是 Linux 系统为了防止用户误删除文件而特意设置的rm
别名命令。
- 可以用
alias
命令来创建一个属于自己的命令别名,格式为 “alias 别名=命令
”。 - 若要取消一个命令别名,则是用
unalias
命令,格式为“unalias 别名
”
判断是内部命令还是外部命令: 使用“type 命令名称
”来判断用户输入的命令是内部命令还是外部命令。
lucky@DESKTOP-VQ8KID4:~$ type help
help is a shell builtin
PATH: PATH是由多个路径值组成的变量,每个路径值之间用冒号间隔,对这些路径的增加和删除操作将影响到 Bash 解释器对 Linux 命令的查找。
Linux 系统中最重要的 10 个环境变量
变量名称 | 作用 |
---|---|
HOME | 用户的主目录,即家目录 |
SHELL | 用户在使用的 Shell 解释器名称 |
HISTSIZE | 输出的历史命令记录条数 |
HISTFILESIZE | 保存的历史命令记录条数 |
邮件保存路径 | |
LANG | 系统语言、语系名称 |
RANDOM | 生成一个随机数字 |
PS1 | Bash 解释器的提示符 |
PATH | 定义解释器搜索用户执行命令的路径 |
EDITOR | 用户默认的文本编辑器 |
Linux 作为一个多用户多任务的操作系统,能够为每个用户提供独立的、合适的工作运行环境,因此,一个相同的变量会因为用户身份的不同而具有不同的值。
变量是由固定的变量名与用户或系统设置的变量值两部分组成的,我们可以自行创建变量,来满足工作需求。例如设置一个名称为 WORKDIR
的变量,方便用户更轻松地进入一个层次较深的目录:
[root@wz /]# WORKDIR=/home/lucky/Desktop/
[root@wz /]# cd $WORKDIR
[root@wz Desktop]#
这样的变量不具有全局性,作用范围也有限,默认情况下不能被其他用户使用。 如果工作需要,可以使用 export
命令将其提升为全局变量,这样其他用户也就可以使用它了:
[root@wz Desktop]# export WORKDIR
[root@wz Desktop]# su lucky
[lucky@wz Desktop]$ cd /
[lucky@wz /]$ cd $WORKDIR
[lucky@wz Desktop]$