接下来,我们把上面的命令,做成一个脚本。然后将这个脚本,放到PATH目录中。不过先等等,我们要先给命令起个名字。
首先需要创建一个文件。在Linux上,创建文件使用touch命令。
# touch jdsjf
命令执行后,什么都没发生,它只是创建了一个空文件。接下来,我们向其中添加一些内容。
# echo "echo 'Hello World'" > jdsjf
注意符号>,它的意思是,将前面的输出,重定向到后面的文件中。执行完上面的命令,jdsjf 中的内容,就变成了echo 'Hello World。
接下来,我们尝试着去执行刚才生成的命令。
# ./jdsjf
-bash: ./jdsjf : Permission denied
我们通过相对路径的方式,来执行刚刚生成的命令。结果,终端显示我们并没有这个命令的执行权限。
其实,Linux在权限控制这一方面,非常的详细。一个文件,有可读、可写、可执行三种属性。如果想要一个文件能够执行,需要给它添加执行权限,这个过程是由命令chmod完成的。
# chmod u+x jdsjf
# ./jdsjf
Hello World
我们将在后面的章节,来详细介绍权限方面的知识。如上所示,命令已经能正常输出,接下来,我们把命令移动到PATH中的一个目录。
# mv jdsjf /usr/local/bin/
# jdsjf
Hello World
不需要加任何的相对路径,现在,只需要输入jdsjf,就可以正常输出一串数字。我们成功地让一个没有任何意义的字符串,表达了它的想法。虽然我们依然是它的主宰。
你可以想一下下面这三个问题:
1、我可以自定义一个目录,比如/root/mybin,把它加入到PATH么?
2、我可以省略上面的touch命令,直接使用重定向生成文件么?
3、除了放到PATH和相对路径,还有没有其他的命令执行方式?
5. Linux漫游方式想要了解linux的基本使用方法,就要了解一个基本的事实--linux系统中,一切皆文件。
不管是命令,还是文档,甚至设备,目录,套接字,在linux上对它们的操作都是一致对待的。许多开发驱动程序的小伙伴,会发现使用的一些函数,和读写文件的没什么两样。今天我们所说的基本操作,针对的就是普通文件和目录,本小节将详细解释相关命令。
5.1、当前路径到现在为止,我们还不知道自己在系统的什么地方。在浏览器上,我们能够通过导航栏上的url,了解到自己在互联网上的具体坐标。相似的功能,是由pwd命令提供的,它能够输出当前的工作目录。
pwd命令是非常非常常用的命令,尤其是在一些命令提示符设置不太友好的机器上。另外,它也经常用在shell脚本中,用来判断当前的运行目录是否符合需求。
有很多线上事故,都是由于没有确认当前目录所引起的。比如rm -rf *这种危险的命令。在执行一些高危命令时,随时确认当前目录,是个好的习惯。
# pwd
/root
我们使用root用户默认登陆后,就停留在/root目录中。Linux中的目录层次,是通过/进行划分的。
Linux的文件系统,从一开始就有一个规范标准。它还有一个专有缩写名词,叫做FHS (Filesystem Hierarchy Standard)。FHS经过多年的演进,目录结构也越来越清晰。除了一些标准的要求,还有一些使用者之间的约定。
接下来,我们大体看一下linux上的默认目录,对其有一个基本的感觉。
第1层第二层介绍/bin目录/usr/bin的软链接/sbin目录/usr/sbin的软链接/lib目录/usr/lib的软链接/usr/bin存放一些常用的命令/usr/sbin存放一些管理员常用的命令/usr/lib用来存放动态库和一些模块文件/sys内核中的数据结构的可视化接口/proc内存映像/run内存映像/boot存放引导程序,内核相关文件/dev存放一些设备文件,比如光盘/etc用于存储一些全局的、应用的配置文件/var与/var/run一样,存放的是系统运行时需要的文件,比如mysql的pid等/tmp非常特殊的临时文件夹,断电丢失/home/**用户目录,比如我的目录是/home/xjjdog/rootroot用户的home目录
linux上的文件类型有很多,它们大部分都分门别类地存放在相应的目录中,比如/dev目录下,就是一些设备文件;/bin文件下,是一些可以执行命令。通常都好记的很。
5.3、查看文件列表所以,上面的表格内容,我是怎么看到的呢,靠记忆么?ls命令,能够列出相关目录的文件信息。可以被评为linux下最勤劳的命令标兵。
现在的终端,都能够输出彩色的信息,非常的直观。oh-my-zsh和oh-my-bash等项目,可以让你的终端更加的漂亮。把它加入到你的研究清单里吧。
# ls /
# 注意:ls可以接受路径参数,你不用先跳转,就可以输出相关信息
bin boot dev etc home lib lib64 media mnt opt proc root run sbin srv sys tmp usr var
# ls -l /
# 带上 -l参数,可以查看一些更加详细的信息。
total 20
lrwxrwxrwx. 1 root root 7 Nov 3 20:24 bin -> usr/bin
dr-xr-xr-x. 5 root root 4096 Nov 3 20:34 boot
drwxr-xr-x. 19 root root 3080 Nov 3 21:19 dev
drwxr-xr-x. 74 root root 8192 Nov 3 20:34 etc
drwxr-xr-x. 2 root root 6 Apr 11 2018 home
lrwxrwxrwx. 1 root root 7 Nov 3 20:24 lib -> usr/lib
lrwxrwxrwx. 1 root root 9 Nov 3 20:24 lib64 -> usr/lib64
drwxr-xr-x. 2 root root 6 Apr 11 2018 media
drwxr-xr-x. 2 root root 6 Apr 11 2018 mnt
drwxr-xr-x. 2 root root 6 Apr 11 2018 opt
dr-xr-xr-x. 108 root root 0 Nov 3 21:19 proc
dr-xr-x---. 2 root root 135 Nov 4 07:53 root
drwxr-xr-x. 24 root root 740 Nov 3 21:20 run
lrwxrwxrwx. 1 root root 8 Nov 3 20:24 sbin -> usr/sbin
drwxr-xr-x. 2 root root 6 Apr 11 2018 srv
dr-xr-xr-x. 13 root root 0 Nov 3 21:19 sys
drwxrwxrwt. 9 root root 4096 Nov 4 03:40 tmp
drwxr-xr-x. 13 root root 155 Nov 3 20:24 usr
drwxr-xr-x. 19 root root 267 Nov 3 20:34 var
ls最常用的,就是加参数l或者参数a。
5.3.1、详细信息加上参数l,能够看到文件的一些权限信息已经更新日期等。但我们还看到了一些更有意思的东西。比如:
lib -> usr/lib
上面表示的,是软链接信息。
就如同我们上面表格所展示的一样,lib目录,是/usr/lib的快捷方式,它们之中的内容,没有什么两样。
关于ls -l展示的更加详细的内容,可以参照我下面的这张图。我们将在了解后面小节的内容后,再次对这张图进行回顾。
5.3.2 隐藏文件直接在你的/root目录里,执行ls -al,你会看到更多东西。这些额外的隐藏文件,都是以.开头,以配置文件居多。这就是参数a的作用。
# ls -al
total 28
dr-xr-x---. 2 root root 135 Nov 4 07:53 .
dr-xr-xr-x. 17 root root 224 Nov 3 20:28 ..
-rw-------. 1 root root 1273 Nov 3 20:28 anaconda-ks.cfg
-rw-------. 1 root root 246 Nov 4 11:41 .bash_history
-rw-r--r--. 1 root root 18 Dec 28 2013 .bash_logout
-rw-r--r--. 1 root root 176 Dec 28 2013 .bash_profile
-rw-r--r--. 1 root root 176 Dec 28 2013 .bashrc
-rw-r--r--. 1 root root 100 Dec 28 2013 .cshrc
-rw-r--r--. 1 root root 129 Dec 28 2013 .tcshrc
细心的同学,应该会注意到两个特殊的目录。.和..。前者表示的是当前目录,而后者表示的是上层目录。
使用cd命令,将在这些目录中,自由穿梭。
5.4、切换目录小技巧:如果你对英文日期阅读困难,可以使用ls -al --full-time查看可读的日期。
执行cd命令,可以将工作目录切换到目标文件夹。为了展示cd命令的效果。请在root用户下,执行下面的命令,这将创建一个7层的目录。
cd
mkdir -p a1/b2/c3/d4/e5/f6/{g7,g8,g9,g10}
我们使用cd命令,切换到最后一层。然后,我们使用..切换到上层目录。
# cd a1/b2/c3/d4/e5/f6/g7
# pwd
/root/a1/b2/c3/d4/e5/f6/g7
# cd ..
# pwd
/root/a1/b2/c3/d4/e5/f6
所以,切换到上面n层目录,只需使用多层级的../即可。有几个特殊的变量,需要说明一下。
我们来使用命令把上面这些特殊变量验证一下。
# 跳转到用户根目录
# cd ~
# pwd
/root
# 进入到第三层目录
# cd a1/b2/c3/
# pwd
/root/a1/b2/c3
# 跳回到前三层目录
# cd ../../..
# pwd
/root
# 跳到上次访问的目录
# cd -
/root/a1/b2/c3
# pwd
/root/a1/b2/c3
# 进入当前目录:等于什么都没干
# cd ./
# pwd
/root/a1/b2/c3
以上就是cd命令的常用用法。现在,我们返回头来看一下mkdir。顾名思义,就是创建目录的意思,但一般在工作中,都会加上-p参数,这样就可以一次性创建多层目录。注意mkdir后面的大括号{},可以一次性地指定多个目录进行创建,这通常能节省很多时间。
5.5、文件操作使用命令行操作文件,是非常方便的。
这四个风骚的命令,主宰着文件资料的去向。我们依然使用上面创建的目录,进行接下来的操作。
# 创建三个文件
# touch long-long-long.txt
# touch 996.txt
# touch icu.txt
# ls
996.txt a1 anaconda-ks.cfg icu.txt long-long-long.txt
# 复制一个文件
# cp 996.txt 007.txt
# mv long-long-long.txt short.txt
# ls
007.txt 996.txt a1 anaconda-ks.cfg icu.txt short.txt
# 移动996.txt到a1目录,icu.txt到a1/b2目录
# 删除short.txt
# mv 996.txt a1/
# mv icu.txt a1/b2/
# rm short.txt
rm: remove regular empty file ‘short.txt’? y
# 递归删除a1目录
# rm -rvf a1/
removed directory: ‘a1/b2/c3/d4/e5/f6/g7’
removed directory: ‘a1/b2/c3/d4/e5/f6/g8’
removed directory: ‘a1/b2/c3/d4/e5/f6/g9’
removed directory: ‘a1/b2/c3/d4/e5/f6/g10’
removed directory: ‘a1/b2/c3/d4/e5/f6’
removed directory: ‘a1/b2/c3/d4/e5’
removed directory: ‘a1/b2/c3/d4’
removed directory: ‘a1/b2/c3’
removed ‘a1/b2/icu.txt’
removed directory: ‘a1/b2’
removed ‘a1/996.txt’
removed directory: ‘a1/’
# ls
007.txt anaconda-ks.cfg
经过一番操作以后,只剩下了007了。除了上面基本的操作,接下来我要介绍一些更加重要的功能。
可以看到在使用rm删除文件的时候,进行了一次提示。这是为了避免误删除一些东西,但有时候,你需要不显示这种提示,就可以加-f参数。f参数对于cp、mv等命令来说,同样适用,它是force的意思
rm -f file
cp -f file1 file2
mv -f file1 file2
另外,还有一个参数-r,这是递归的意思。我们的目录和文件,通常有多个层次,递归可以把操作全部作用于上面,比如上面的递归删除a1目录。
# 警告:以下命令会造成严重后果
rm -rf /
上面的这个命令,你一定经常看到。这不是笑话,已经有很多用户因此丢失了数据,这就是传说中的删根,最终你将一无所有。那参数v又是干什么用的呢?加上它之后,可以看到命令详细的执行过程。在平常的操作中,我一般都加上。
6.开始操作文件你可能已经了解到,ll -l命令的第一列,能够显示linux的文件类型。请对此有一个大体的印象,因为后面的很多命令,会用到这些知识。
Linux上的文件可以没有后缀,而且可以创建一些违背直觉的文件。比如后缀是png,但它却是一个压缩文件。大学时,就有聪明的同学这样看小电影,效果很好。
查看文件的具体类型,可以使用file命令,它很聪明,能够识别很多文件格式。
# file /etc
/etc: directory
# file /etc/group
/etc/group: ASCII text
# file /dev/log
/dev/log: socket
# file /dev/log
/dev/log: socket
# file /bin
/bin: symbolic link to `usr/bin'
本部分的操作,面向的就是 ASCII text类型的,普通文本文件。接下来,我们要创建一些文件。然后写入一些内容到文件里,以便进行后续的操作。
6.1、创建一个文件6.1.1、数字序列使用重定向符,能够直接生成文件。下面,我要生成10到20的数字,每一个数字单独一行,写入一个叫做spring的文件。巧的很,seq命令可以完成这个过程。
seq 10 20 >> spring
我们在前面提到过>的意思,是将前面命令的输出,重定向到其他地方。在这里,我们用了两个>,它依然是重定向的意思,但表示的是,在原来文件的基础上,追加内容。
也就是编程语言里的w+和a+的意思。
6.1.2、查看内容为了查看文件的生成效果,可以使用cat命令检测。cat命令将会把文件的内容,输出打印到终端上。如果加上参数n,甚至可以打印行号。效果如下:
# cat spring
# cat -n spring
除了查看文件内容,cat命令通常用在更多的地方。只有和其他命令联合起来,它才会觉得生活有意义。
# 合并a文件和b文件到c文件
cat a b>> c
# 把a文件的内容作为输入,使用管道处理。我们在后面介绍
cat a | cmd
# 写入内容到指定文件。在shell脚本中非常常用。我们在后面会多次用到这种写法
cat > index.html <<EOF
<html>
<head><title></title></head>
<body></body>
</html>
EOF
由于我们的文件不大,cat命令没有什么危害。但假如文件有几个GB,使用cat就危险的多,这只叫做猫的小命令,会在终端上疯狂地进行输出,你可以通过多次按ctrl+c来终止它。
6.2、平和地查看文件既然cat命令不适合操作大文件,那一定有替换的方案。less和more就是。由于less的加载速度比more快一些,所以现在一般都使用less。它最主要的用途,是用来分页浏览文件内容,并提供一些快速查找的方式。less是一个交互式的命令,你需要使用一些快捷键来控制它。
这次我们使用seq生成一千万行记录,足足有76MB大小,然后用less打开它。
# seq 10000000 > spring
# du -h spring
76M spring
# less spring
关于less,一般操作如下:
head可以显示文件头,tail可以显示文件尾。它们都可以通过参数-n,来指定相应的行数。
# head -n 3 spring
# tail -n 3 spring
9999998
9999999
10000000
对于部分程序员来说,tail -f或许是最常用的命令之一。它可以在控制终端,实时监控文件的变化,来看一些滚动日志。比如查看nginx或者tomcat日志等等。通常情况下,日志滚动的过快,依然会造成一些困扰,需要配合grep命令达到过滤效果。
# 滚动查看系统日志
tail -f /var/log/messages
# 滚动查看包含info字样的日志信息
tail -f /var/log/messages | grep info
6.4、查找文件对于tail命令来说,还有一个大写的参数F。这个参数,能够监控到重新创建的文件。比如像一些log4j等日志是按天滚动的,tail -f无法监控到这种变化。
考虑下面这个场景。我们需要找一个叫做decorator.py的文件,这个文件是个幽灵,可能存在于系统的任何地方。find命令,能够胜任这次捉鬼行动。
我们使用find命令,从根目录找起,由于系统的文件过多,下面的命令可能会花费一段时间。
# find / -name decorator.py -type f
/usr/lib/python2.7/site-packages/decorator.py
使用time命令,可以看到具体的执行时间。执行还是挺快的么!秒出!
# time find / -name decorator.py -type f
/usr/lib/python2.7/site-packages/decorator.py
real 0m0.228s
user 0m0.098s
sys 0m0.111s
find命令会查出一个路径的集合。通常是查询出来之后,进行额外的处理操作,一般配合xargs命令使用,至于find的exec参数?忘了它吧,不好用!
# 删除当前目录中的所有class文件
find . | grep .class$ | xargs rm -rvf
# 找到/root下一天前访问的文件,type后面的类型参见文章开头
find /root -atime 1 -type f
# 查找10分钟内更新过的文件
find /root -cmin -10
# 找到归属于root用户的文件
find /root -user root
# 找到大于1MB的文件,进行清理
find /root -size +1024k -type f | xargs rm -f
find的参数非常非常多,记不住怎么办?除了常用的,其实都可以通过man命令查看。man的操作也和vi非常的类似,输入/EXAMPLES,会看到很多样例。不过我觉得还是上面列出的这些命令更加的适用。
6.4.1、数据来源在上图中,你会看到mtime,ctime,atime类似的字样,它们的数据来自于何处呢?接下来我们顺理成章地看一下stat命令。
# stat spring
File: ‘spring’
Size: 78888897 Blocks: 154080 IO Block: 4096 regular file
Device: fd00h/64768d Inode: 8409203 Links: 1
Access: (0644/-rw-r--r--) Uid: ( 0/ root) Gid: ( 0/ root)
Context: unconfined_u:object_r:admin_home_t:s0
Access: 2019-11-04 18:01:46.698635718 -0500
Modify: 2019-11-04 17:59:38.823458157 -0500
Change: 2019-11-04 17:59:38.823458157 -0500
Birth: -
这不就是文件属性么?从文件大小,到文件类型,甚至到最后修改、访问时间,都可以从这里获取。Linux文件系统以块为单位存储信息,为了找到某一个文件所在存储空间的位置,会用i节点(inode) 对每个文件进行索引,你可以认为它是一个文件指针。
关于inode是一个比较大的话题,也是比较重要的知识点,有兴趣的可以自行搜索。我们只需要知道这些信息是从这里来的就可以了。
如果我只想获取Modify这个数值,可以组合使用一下上面写到的命令。首先获取最后三行,然后获取首行。效果如下:
# stat spring | tail -n 3 | head -n 1
Modify: 2019-11-04 17:59:38.823458157 -0500
下面几个命令,效果是与上面等价的,输出结果也是一模一样。正所谓条条大路通罗马,接下来,我们首先介绍一下出现频率较高的grep。另外,我们在上面的这些命令中,多次使用了|,这是Linux中非常重要的管道概念,下面也会着重介绍。
stat spring | head -n 7 | tail -n 1
stat spring | grep Modify
stat spring | sed -n '7p'
stat spring | awk 'NR==7'6.5、字符串匹配
grep用来对内容进行过滤,带上--color参数,可以在支持的终端可以打印彩色,参数n则用来输出具体的行数,用来快速定位。这是一个必须要熟练使用的命令。
比如:查看nginx日志中的POST请求。
grep -rn --color POST access.log
推荐每次都使用这样的参数。
如果我想要看某个异常前后相关的内容,就可以使用ABC参数。它们是几个单词的缩写,经常被使用。
就像是这样:
# 查看Exception关键字的前2行和后10行
grep -rn --color Exception -A10 -B2 error.log
#查找/usr/下所有import关键字,已经它们所在的文件和行数
grep -rn --color import /usr/6.6、管道
在上面的命令中,我们多次用到了|,这貌似可以完成一些神奇的事情。|是pipe的意思,它可以把多个命令联系起来。通常,命令有下面的关联方式:
前三种的命令关联,是非常简单有逻辑的,非常的好理解。而管道,却有自己的特点。
接触过编程语言的都知道stdin、stdout、stderr的概念。让我们重新组织一下针对于管道的定义:前面命令的输出(stdin),将作为后面命令的输入(stdout)。
我们拿一行命令来说明。
seq 20 100 | head -n 50 | tail -n 1
上面命令,将输出69。69是个神奇的数字,它是怎么办到的呢?我们来一张小图,一切就豁然开朗了。
关于输入输出和错误,linux使用一个数字进行缩写,这在一些脚本中,甚至在一些安装文件中,会经常用到。
通过类似2>&1的语法,可以把错误信息定向到标准输出。我们用命令来证明一下。
# 错误信息无法输出到文件
# cat aaaaaaaaa > b
cat: aaaaaaaaa: No such file or directory
# cat b
# 错误信息被重定向了
# cat aaaaaaaaa > b 2>&1
# cat b
cat: aaaaaaaaa: No such file or directory