常用shell指令-文件相关
常用shell指令-文件相关
一.创建文件
1
2
3 $ echo "Hello World!" > text # 创建文件text, 并且文件中包含内容"Hello World!" >表示重定向输出流
$ touch text1 text2 text3 # 创建空文件text1, text2, text3 (要求text1,text2,text3不存在)
$ vim hello.c # 编辑hello.c, 按:wq退出。
echo
单词有回响、余音的意思,它可以直接echo 字符串
表示将字符串输出到标准输出(一般是屏幕)中。上面指令中的>
字符是一个重定向操作符,它表示不再输出到标准输出中,而是输出到文件text
中。若文件不存在,则会创建文件。touch
单词是触摸的意思,touch 文件名...
作用是文件不存在则创建文件,若存在则将文件的最后修改时间更新。vim
是后续我们最常用的方式,它也可以用于创建多个文件。关于vim的详细使用,我们在后续章节继续学习。
二.查找文件
1.which查找可执行文件
1
2
3 $ which bash # 查看bash的路径
$ which ls tree # 查看命令ls和tree的路径
$ which -a vim # 查看vim的所有路径 (我们可能装了多个版本的vim)which是根据PATH环境变量中的路径依次去查找的,然后显示第一个匹配项,或者显示所有匹配项
效果:
PATH环境变量是什么?
PATH环境变量是一个包含一系列目录路径的变量,用于告诉操作系统 shell 在哪些目录中查找可执行文件。(Windows也有类似的)
当你在终端输入一个命令时,系统会按照PATH环境变量中指定的顺序搜索这些目录,直到找到匹配的可执行文件为止。
在以往我们给大家演示过一个指令:
./hello.py
该指令用于执行一个可执行文件,那么你现在就可以思考一下这个指令为什么不能写成
hello.py
直接执行这个文件呢?为什么非要加一个表示当前工作目录的
./
呢?这是因为直接写
hello.py
,Linux会把整体当成一个指令去PATH环境变量下寻找可执行程序,但很明显这是找不到的,所以会报错:hello.py:未找到命令
而使用了
./
就不会去PATH环境变量下寻找了,而是直接在当前工作目录下,找到当前工作目录下的可执行程序进而执行。可以使用env查看PATH环境变量
1 $ env效果
2.find命令
find命令可以在一个目录或者多个目录中,递归的查找符合指定条件的文件或者目录
该指令可以用于查找文件,也可以用于查找目录,基本格式
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71 $ man find
find - search for files in a directory hierarchy
#在目录层次结构中搜索文件
格式:
find [起始点...] 查找条件选项
# 起始点表示查找文件从哪个目录开始,或者哪几个目录开始
# 起始点是可以省略的,省略后会从当前工作目录开始进行查找工作
# 建议不要省略起始点,若从当前目录开始查找时,可以使用 . 来表示当前目录
常用选项:
-name pattern
#查找符合pattern名字的文件或目录
#pattern名字最好要使用""包裹起来,这样可读性更好也能避免执行出错
#可以使用我们以往学习的通配符,使用通配符时必须用""包裹
-type c
#查找类型为c的文件
#常见的文件类型表示字符如下:
#b(block): 块设备文件
#c(character): 字符设备文件
#d(directory): 目录
#p(named pipe): 有名管道
#f(file): 普通文件(和ls -l时用-表示有区别,这里要记住)
#l(symbolic link): 符号链接
#s(socket): 套接字
-size n[单位]
#根据一个文件的大小进行查找
#n必须是一个非负数
#单位即内存大小的单位,如下:
#c: 字节
#w: 两个字节,即1个字
#b: 512个字节 (注意如果不添加单位的话,b是默认值)
#k: kb, 1024个字节
#M: Mb, 1024kb
#G: Gb, 1024Mb
#当仅填入一个非负数时,表示文件大小必须精确匹配指定的大小.如: -size 100c 表示精确查找100个字节的文件
#当填入一个非负数且在n前面添加正负号时, +正号表示查找大于指定大小的文件, -负号表示查找小于指定大小的文件
# -size +1k 表示文件大小必须大于1kb
# -size -100M 表示文件大小必须小于100Mb
#不要用这个选项查找目录, 目录的大小不是你想象中目录下所有文件和子目录大小之和,这一点上面已经讲解过了
-empty
#查找空的文件或空的目录文件
-user username
-uid uid
#根据用户名或者UID查找
#可以通过 cat /etc/passwd 命令来查看Linux用户信息,如UID
#也通过组名和组ID也可以查找, 但目前组基本上没人用, 这里就不赘述了
-perm 权限数字
#根据权限查找
#比较常见的权限数字,比如775,664等
#根据时间查找的选项
-(时间类型)(min/time) 正整数
#时间类型指查找依据的时间类型
#a(access): 文件访问的时间
#c(change): 文件元数据发生改变的时间
#m(modify): 文件内容发生改变的时间
#min:时间以分钟为单位
#time: 以天为单位
#n是一个整数表示对应时间,可以在n前面添加'+'和'-',表示大于和小于
-maxdepth n
#指定递归搜索的深度为n
#若只想在当前目录下搜索,可以设定-maxdepth 1
#组合查找:
-a(and), -o(or), !(not)
#分别表示组合查找的与、或、非
1
2
3
4
5
6
7
8
9
10
11
12
13
14 $ find /usr/include -name "stdio.h" # 在/usr/include目录下查找stdio.h文件
$ find . -name "*.c" # 在当前工作目录下查找所有以.c结尾的文件
$ find /dev -type b # 在/dev目录下查找所有的块设备文件
$ find . -size 5M # 在当前工作目录下查找所有大小为5M的文件
$ find . -size +5M # 在当前工作目录下查找所有大于5M的文件
$ find dir1 dir2 dir3 -empty # 在dir1,dir2,dir3目录下查找所有空的文件和空的文件夹
$ find . -user he # 在当前工作目录下查找he用户拥有的文件
$ find . -gid 0 # 在当前工作目录下查找root组(gid=0)拥有的文件
$ find . -perm 664 # 在当前工作目录下查找权限为664(rw-rw-r--)的文件
$ find . -mtime 1 # 在当前工作目录下查找在[1, 2)天前内容发生修改的文件 (find会省略小数部分)
$ find . -mtime +2 # 在当前工作目录下查找在[3, +)天前内容发生修改的文件
$ find /dev -type c -a -name "tty*" # 在/dev目录下查找以tty开头的字符设备文件
$ find /dev -type b -o -name "tty*" # 在/dev目录下查找块设备文件或者是以tty开头的文件
$ find /dev -type c -a ! -name "tty*" # 在/dev目录下查找不以tty开头的字符设备文件注意:在查找当前目录时,建议使用
.
来表示当前目录,虽然也可以直接省略。
find
命令的选项很多,而且允许组合起来进行查找,此时需要使用选项-a
表示并且,-o
表示或者,-!
表示否定。查找c语言模板文件就用到了find
效果
3.cat查看文件内容
用法:
1
2
3 $ cat /etc/passwd #在屏幕上打印用户相关的信息
$ cat -n /etc/passwd #在屏幕上打印用户相关的信息,显示行数
$ sudo cat /etc/passwd /etc/shadow #在屏幕上打印用户的密码,但密码也都是加密存储的效果:
4.head和tail查看文件内容首尾
head命令用来查看文件内容的前几行
用法
1
2
3
4 $ head text1 #显示text1的前10行
$ head text1 text2 text3 #显示text1,text2,text3的前10行
$ head -n 5 text1 #显示text1的前5行
$ head -n -5 text1 #显示除了最后5行外的所有行tail命令用来查看文件内容的后几行
用法
1
2
3
4
5 $ tail text1 # 显示text1的后10行
$ tail text1 text2 text3 # 显示text1,text2,text3的后10行
$ tail -n 5 text1 # 显示text1的后5行
$ tail -n +5 text1 # 从第5行开始显示,直到文件末尾
$ tail -F error.log # 查看错误日志文件,显示后10行,并且会实时显示后续追加的数据尤其需要处理-F选项,添加后tail会处于持续执行监听的状态,若文件末尾进行了数据追加 则会实时显示出来,这个指令常用来查看日志文件,比较常用.
5.grep搜索文件内容
grep是词组”globally search for a regular expression”的缩写,意为根据一个正则表达式进行全局搜索,它通常用于对文件内容进行搜索,功能十分强大,也很好用.
具体而言,该指令搜索的逻辑是:
按正则表达式去搜索匹配文件内容,如果文件中某一行匹配指定的正则表达式,grep命令则会显示这一行。
惯用法:
1
2
3
4
5 grep -nE "firmament" The_Holy_Bible.txt # 显示包含"firmament"的所有行内容,并显示行号
grep -niE "GOD" The_Holy_Bible.txt # 忽略大小写的显示包含"GOD"的所有行内容,并显示行号。
grep -nvE "god" The_Holy_Bible.txt # 显示不包含"god"的所有行内容,并显示行号。
grep -cE "god" The_Holy_Bible.txt # 统计文件中包含"god"的总行数,打印出来。不打印任何文件内容
grep -cvE "god" The_Holy_Bible.txt # 统计文件中不包含"god"的总行数,打印出来。不打印任何文件内容
三.重定向指令
重定向不是改变进程和缓冲区之间的关联,而是改变缓冲区和源和目的地
解释一下这些重定向符号:
- <:将文件的内容重定向到命令的输入,一般比较少使用。
- >:将命令的标准输出重定向到一个文件中,如果文件已经存在,则从头覆盖文件内容。
- >>:将命令的标准输出追加到一个文件的末尾,如果文件t不存在,则创建文件。
2> 和 2>>
类似标准输出流的重定向,只不过改成了标准错误输出。重定向配合cat、heah、tail、echo等命令的使用
1
2
3
4
5
6
7
8
9
10 $ who > users #将原本输出到屏幕上的当前用户的信息输出到文件users中
$ echo "faker is a fake" >> users #将原本输出到屏幕上的字符串信息追加写入到文件users中
$ wc -l < users #将默认键盘输入重定向从文件users读取数据,它从效果上基本等价于wc users
# 在file1不存在的前提下执行下列命令
# 此时cat指令会将users的内容输出到stdout,默认打印到屏幕
# 并且还会将file1不存在的错误信息输出到stdout,默认打印到屏幕
$ cat users file1 > text # 重定向stdout,将users文件内容打印到文件text中
$ cat users file1 2> text # 重定向stderr,将file1文件不存在的错误信息打印到文件text中
$ cat users file1 >& text # 同时重定向stdout和stderr,将文件内容和错误信息同步输出到文件text中wc指令和重定向
wc(word count)指令是一个用于统计输入数据中行数,单词数和字符数的指令
wc后面如果不跟任何文件名,它会从标准输入(键盘)中读取数据然后进行统计
在linux中在命令输入ctrl+d表示输入EOF,结束键盘录入
该指令如果紧跟文件名,表示从文件中读取数据,然后输出统计的结果。
比如:
wc text
和wc < text
,它们两个从效果上来说基本是等价的,如下图所示
发现直接跟文件名,输出结果中会多一个文件名,这是因为
wc < 1_text直接重定向了stdin缓冲区,wc进程只知道数据是从stdin缓冲区来的,但是他不知道数据源已经从键盘变成了文件,因此还是按键盘录入处理的,而直接跟文件名,wc 1_text的数据是来源于text的文件缓冲区的,自然直到数据源文件的名字
四.命令的组合
1.概述
shell命令是可以进行组合使用的,基于命令的组合,可以增强一些指令的作用。比如grep,就可以利用组合命令,大大增强它的功能。
命令的组合主要有三种方式:
cmd ; cmd2
,即两条指令间使用分号隔开,这个组合很简单就是单纯的先执行命令1,然后执行命令2。例如:
mkdir dir; cd dir
- 先创建dir目录,然后cd进入该目录
cmd1 | cmd2
,其中”|”是管道,整个命令表示将cmd1指令输出的结果,作为cmd2指令的输入。cmd1 | xargs cmd2
,表示将cmd1输出结果的每一行作为cmd2指令执行的输入参数。
2.管道
|
是字符竖线,不是大写字母I,它表示管道,管道是进程间通信的一种方式,从效果上看:
cmd1 | cmd2
就表示将cmd1指令执行的输出结果,作为cmd2指令的输入。管道在这里是什么原理呢?
cmd1
和cmd2
指令的执行实际上是启动了两个进程,整个管道的原理如下图所示:
管道是操作系统内核提供一种系统功能,它可以被想象为一个缓冲区队列,用于存储从管道一端输入的数据,直到另一端的进程读取它。
管道允许数据从一个进程流向另一个进程,是进程间通信的重要手段。
具体到
cmd1 | cmd2
指令:cmd1指令的进程会将stdout输出重定向到管道中,也就是cmd1进程的输出不再打印到屏幕上,而是将数据放入管道;
cmd2指令的进程会将stdin输入重定向到同一管道中,也就是cmd1进程的输入不再是从键盘接收录入,而是从管道读取数据。
于是
cmd1 | cmd2
指令就实现了:将cmd1指令的输出结果,作为cmd2指令的输入数据。
3.管道“|”应用举例
history
指令会将当前会话输入的shell指令的历史输出到stdout中,进而打印在屏幕上。
tail -n 5
指令在不输入文件名的情况下会从stdin接收数据(默认是从键盘),然后将后5行输出到stdout中(默认是输出到屏幕中)。现在把它们用管道组合起来,得到组合指令:
1 history | tail -n 5效果是什么呢?
很简单:
history
指令的输出作为tail -n 5
指令的输入,总的效果就是打印shell指令历史的后5行。
再举一些例子:
ls -lh | grep -E "test"
:列出当前目录的详细列表,并通过grep
搜索包含”test”的行。
tail -f /var/log/server.log | grep -niE "error"
:持续显示系统日志文件中最新的内容,并且只显示包含”error”的行。
4.管道“| xargs”应用举例
xargs 是词组”extended arguments”的缩写,意为扩展的参数。
组合命令
cmd1 | xargs cmd2
的含义是:将cmd1指令输出的每一行,分别作为参数,传递给cmd2指令。使用举例:
比如现在的需求是:查找当前目录下所有的.c文件,然后找到文件内容中存在main函数的行。
这明显是一个组合需求:
- 查找当前目录下所有的.c文件:可以用指令
find . -name "*.c"
- 查找某个.c文件中存在main函数的行:可以用指令
grep -nE "\<main\(" xxx.c
利用xargs和管道,我们可以将这两个指令组合,得到指令:
find . -name "*.c" | xargs grep -nE "\<main\("
就可以实现需求了。
那么思考一下:
1 find . -name "*.c" | xargs grep -nE "\<main\("和
1 find . -name "*.c" | grep -nE "\<main\("有什么区别呢?
第一个是将|之前的结果都作为|后面的参数,即查找的是文件的内容,第二个是直接查找的是|找到的路径名里面的main