22

我以前经常在网上查类似于“在Ubuntu下如何让某个用户对某个文件夹拥有可读可写的权限?”,“Mac上如何通过命令行启动某个程序?”,“在Linux中如何彻底卸载某个软件?”这类的问题,当然这类问题都可以较容易的在网上找到解决方案,但是每次解决我都是知其然不知其所以然,所以当下次我碰到类似的问题时,我还是要花一定的时间去查,这让我有一种挫败感;开发相关的知识大多变得特别快,但是有些知识特别经典,其实比起某些库或框架也许更值得系统的了解。这也是本文的写作初衷,一方面是自己对近两个月来看的相关资料做一个总结,另一方面也希望可以帮助Linux初学者更好的理解,运用这个系统。

概述

第一次安装Linux

在我大二的时候,学校里有个学长就《神奇的Ubuntu》为题进行了一次演讲(演讲我并没去听,但是仔细看了那个手绘的宣传板,当时觉得很有意思,不过到现在过了七年多了,也实在是不记得宣传板上具体的内容了,依稀记得把Windows批判了一番。。)。

在那个好奇心最重的年龄,我回去就开始查关于Ubuntu相关的消息,发现它是Linux的众多发行版之一,其它发行版还有centos,redHat,Fedora等等,又不知道从哪里看到,Ubuntu还和MacOS 有一定的亲缘关系(都是类Unix系统),瞬间就懂了尝试使用的心,连夜下载了当时最新的Ubuntu发行版(应该是Ubuntu10.04),覆盖安装了本机的Win7系统(当时刚买电脑半年,那时候还不知道还有虚拟机这个东西),当时就觉得利用命令行下载软件特别酷,尝试了酷炫的3D桌面,寻找了windows相关软件的替代品,不过大概还是10天左右还是由于各种原因就又换回了Windows(其实当时也并没有理解这个系统)。

可能也是一直念念不忘这个系统,后来又安装了好几次,有装双系统,有用虚拟机,有用Docker,有用阿里云的远程服务器等等。就我自己的体验来看,我最推荐的安装方式还是使用虚拟机,virtualbox是一个开源的免费的虚拟机软件(支持MacOS和Windows),在Linux发行版官网下载好想使用的Linux系统后(比如Ubuntu16.04桌面版,本文之后的代码也大多基于Ubuntu,有的也使用了Mac),通过虚拟机进行安装即可,虚拟机的使用非常简单,聪明的你肯定一试就会。

从Linux图形界面的说起

在Windows下,我们习惯于使用各种具有完善图形界面的软件,毫无疑问,图形界面大大降低了普通人使用电脑的成本,甚至个人计算机的普及,图形界面都功不可没,在Linux下也有图形界面(俗话说的桌面),通过以下文字,我们可以对其有初步的了解:

相对于现在的 Windows 系统,UNIX/Linux 本身是没有图形界面的,我们通常在 UNIX/Linux 发行版上看到的图形界面实际都只是运行在 Linux 系统之上的一套软件,而 Linux 上的这套软件以前是 XFree86,现在则是 xorg(X.Org),而这套软件又是通过 X 窗口系统(X Window System,也常被称为 X11 或 X)实现的,X 本身只是工具包及架构协议,而 xorg 便是 X 架构规范的一个实现体,也就是说它是实现了 X 协议规范的一个提供图形界面服务的服务器,就像实现了 http 协议提供 web 服务的 Apache 。如果只有服务器也是不能实现一个完整的桌面环境的,当然还需要一个客户端,我们称为 X Client,像如下几个大家熟知也最流行的实现了客户端功能的桌面环境 KDE,GNOME,XFCE,LXDE 。
注:以上文字引自实验楼《Linux基础入门》

当然也许你早就知道Linux的正确打开方式是使用命令行(呃..啥是命令行?),不过看了对Linux图形界面的描述后,是不是更加理解为啥我们要用命令行了。那接下来就说说啥是命令行?

命令行、终端,shell和console

?,呃,慢着,不是说好解释啥是命令行么,怎么突然冒出了四个名词。熟悉又模式的四个词,别急,我们一个个来解释。

命令行(CLI)

命令行界面是相对于图形界面而言的,较图形用户界面节约计算机系统的资源。在熟记命令的前提下,使用命令行界面往往要较使用图形用户界面的操作速度要快。命令行中,可以使用脚本语言和宏语言,以其提供更加丰富的控制与自动化的系统管理能力。命令行界面-维基百科

终端(Terminal)

终端特指计算机或通信网络中输入或输出信息的装置,通常由键盘和显示器等组成。但是使用Mac或者安装好了Ubuntu的童鞋会发现有一个程序也叫终端(Terminal),在某种意义上,终端还是我们与系统交互的窗口,严格来讲,我们现在在系统中运行的终端程序只是终端模拟器(常见的终端模拟器有以下几个: gnome-terminal,kconsole,xterm,rxvt,kvt,nxterm 和 eterm),更多关于终端的描述,可以参考这篇文章

这里还得插一句:终端本质上是对应着 Linux 上的 /dev/tty 设备(设备稍后详述),Linux 的多用户登陆就是通过不同的 /dev/tty 设备完成的.

shell

英语好的同学一下子就可以看出shell是壳的意思,有壳就有核,核指的是 UNIX/Linux 内核,Shell之所以叫Shell 是因为它隐藏了操作系统底层的细节。我们可以换个大家一下就能懂的词来理解Shell:命令解析器

当我们在终端中输入node,按回车,会启用node解释器,输入python按回车会启动Python解释器,之后就可以在里面输入并执行对应语言的代码啦。

在 UNIX/Linux 中比较流行的常见的 Shell 有 bashzsh(用没用过美美的oh my zsh)、kshcsh 等等,Ubuntu 终端默认使用的是 bash。本文后面对shell命令的讲解也大多基于bash。

console

从字面上来讲,console是控制台的意思,现在的console一般与终端在外表上没什么区别,不过其在功能上却大不相同,console的出现有其历史原因,简单的说来,就是在以前电脑还是很稀缺的物件的年代,一台电脑是会陪伴多套终端的,这时候就需要专门的系统管理员利用console来管理系统。目前对一般人来说console的作用可能没有那么大了,不过可能其还是会在一些特殊场景下有很大的作用,具体我也不是很清楚,在此就不阐述了。

终端的分类:

终端分字符终端图形终端,字符终端(Character Terminal)也叫文本终端(Text Terminal),是只能接收和输出文本信息的终端。图形终端(Graphics Terminal)不但可以接收和输出文本信息,也可以输出图形图像。

一般说来字符终端的的标准是DEC公司1978制造的型号为VT100的终端。而图形终端的标准是X Window,它是大多数Unix-like系统GUI界面的基础,xterm是Unix世界里最著名的图形终端模拟程序。

以Ubuntu具体说来,它默认提供七个终端,其中第一个到第六个虚拟控制台是全屏的字符终端,第七个虚拟控制台是图形终端,用来运行GUI程序,按快捷键CTRL+ALT+F1,或CTRL+ALT+F2…….CTRL+ALT+F6,CTRL+ALT+F7可完成对应的切换,安装了虚拟机的童鞋可以动手尝试一下哈。

开始使用Shell

shell可能是我们在Linux下使用最多的工具了,本小节我们我们以bash为例,当然zsh下以下命令也是适用的,我们先熟悉一下shell的基本操作。

对输入输出的描述

命令行的操作分为输入和输出两个方面:

输入:打开终端,按键盘输入,按回车结束输入并执行;
输出:输出会返回你想要的结果,比如你看的是文件,就会返回文件的内容。如果是执行的程序,执行失败会告诉你哪里错了,如果施行成功会没有输出,这是linux的哲学:没有结果就是最好的结果。

提高shell的输入效率

我还记得在我初用Mac终端(shell为zsh)时,有人告诉我输入文件目录时,输入几个字母后按tap键,可以自动补全,当时觉得特别神奇,还特意向我不是学计算机的同学炫耀,命令行有多么好用。合理的使用快捷键确实可以明显的提高工作效率,对shell常用快捷键的总结如下:

  • Tap:点击Tab键可以实现命令补全,目录补全、命令参数补全;

  • Ctrl+c:强行终止当前程序(常用);

  • Ctrl+d:键盘输入结束或退出终端(常用);

  • Ctrl+s:暂停当前程序,暂停后按下任意键恢复运行;

  • Ctrl+z:将当前程序放到后台运行,恢复到前台为命令fg;

  • Ctrl+a:将光标移至输入行头,相当于Home键;

  • Ctrl+e:将光标移至输入行末,相当于End键;

  • Ctrl+k:删除从光标所在位置到行末,常配合ctrl+a使用;

  • Alt+Backspace:向前删除一个单词,常配合ctrl+e使用;

  • Shift+PgUp:将终端显示向上滚动;

  • Shift+PgDn:将终端显示向下滚动;

  • 上下方向键:浏览历史输入记录;

熟练运用上述的操作技巧将大大提升我们命令行的操作效率,不过真正解决问题需要应用各种bash命令,下面对常用命令进行简单的介绍:

常见的bash命令

文件相关

  1. ls:列出某文件夹下的文件,添加参数可实现更细致的功能,

    • ls -a 列出所有文件,包括隐藏文件

    • ls -l 列出文件及其详细信息

  2. cd切换目录,cd到不存在的目录时会报错

  3. pwd打印当前目录

  4. cat:读取某一个文件内的内容

  5. wc:获取某一个文件的行数和字数

$ wc package.json
# 79     175    2712 package.json
  1. cp:复制某文件

  2. mkdir:创建目录

  3. rmdir:删除目录

  4. rm-rf:r删除内部所有文件,f参数表示强制,rm -r junk删除junk目录及其下面的所有文件;

  5. mv移动 mv photos.jpg Photos 将photos移动到文件夹Photos

  6. sort排序

  7. diff:比较两个文件的异同

系统相关:

  1. date:获取当前时间

  2. uname:返回系统名称

  3. hostname:返回系统的主机名称

网络相关:

  1. host xx.xxx.com:显示某域名相关托管服务器/邮件服务器

  2. ping 8.8.8.8检测连接

搜索相关命令:

  1. whereis:

    • 描述:简单快捷

    • 使用$whereis who

    • 说明:这个搜索很快,因为它并没有从硬盘中依次查找,而是直接从数据库中查询。whereis 只能搜索二进制文件(-b),man 帮助文件(-m)和源代码文件(-s)。

  2. locate:

    • 描述:快而全

    • 使用$ locate /etc/sh(查找 /etc 下所有以 sh 开头的文件),$ locate /usr/share/\*.jpg(注意要添加 * 号前面的反斜杠转义,否则会无法找到。)

    • 说明:通过/var/lib/mlocate/mlocate.db 数据库查找,不过这个数据库也不是实时更新的,系统会使用定时任务每天自动执行 updatedb 命令更新一次,所以有时候你刚添加的文件,它可能会找不到,需要手动执行一次 updatedb 命令(在我们的环境中必须先执行一次该命令)。它可以用来查找指定目录下的不同文件类型

    • 可带参数:如-i 参数可以忽略大小写进行查找

  3. which:

    • 描述:小而精

    • 使用:$ which man

    • 说明:我们通常使用 which 来确定是否安装了某个指定的软件,因为它只从 PATH 环境变量指定的路径中去搜索命令

  • find:

    • 描述:精而细

    • 使用:$ sudo find /etc/ -name interfaces/格式find [path] [option] [action];

    • 说明:find 应该是这几个命令中最强大的了,它不但可以通过文件类型、文件名进行查找而且可以根据文件的属性(如文件的时间戳,文件的权限等)进行搜索。find很强大也相对而言很复杂,在此先不赘述;
      $ sudo find /etc/ -name \*.list

其它:

  1. --version/-V查看某个程序的版本

  2. history显示历史

  3. echo:返回你给的值,可以简单理解为js中的console或python中的print

  4. man使用一个叫做less的程序,查看某个命令的帮助文档

  5. less:linenumer u d keyarray search(大小写敏感),正则表达式

通配符(Globbing):

 - 使用命令时可在参数中使用通配符
  - `*`:匹配 0 或多个字符,如`ls *.html`将匹配所有以html结尾的文件,`ls b*.png`将匹配所有以b开头,png结尾的文件;
  - `?`:匹配任意一个字符,如`ls abc?.png` 可匹配abcd.png/abce.png
  - `[list]`:匹配 list 中的任意单一字符
  - `[!list]`:匹配 除list 中的任意单一字符以外的字符
  - `[c1-c2]`:匹配 c1-c2 中的任意单一字符 如:[0-9] [a-z]
  - `{string1,string2,...}`:匹配 string1 或 string2 (或更多)其一字符串,如 `{css,html}`, `ls app.{html.css}`将匹配app.css 和app.html;
  - `{c1..c2}`:匹配 c1-c2 中全部字符 如{1..10}
 - 使用`man`查看帮助(man分类如下:)
 -  注意通配符大小写敏感

上文只对常见命令进行了简单的描述,其中一些命令在下文讲到具体应用场景时还会详细的说明。结合刚刚所说的这些命令,我们来理解Linux是一个怎么样的系统。

Linux的核心系统

有没有想过这样一个问题,我们可以很容易通过外貌等特征认出某台计算机是属于我们自己的,那反过来,计算机是怎么识别目前正在操作的那个人是你呢?就Linux而言,这就涉及到用户管理系统。

用户管理系统

Linux 是一个可以实现多用户登陆的操作系统,多用户可以同时登陆同一台主机,共享主机的一些资源,不同的用户也分别有自己的用户空间,可用于存放各自的文件。虽然不同用户的文件是放在同一个物理磁盘上的甚至同一个逻辑分区或者目录里,但是由于 Linux 的用户管理和 文件权限机制,不同用户不可以轻易地查看、修改彼此的文件。

那先看看我们是谁?

查看用户

查看当前用户有多种方式可以实现,我们试试下面三种命令:

  • $ who am i:只列出用户名

  • $ who mom likes/who am i:列出用户名,所使用终端的编号和开启时间;

  • $ finger:列出当前用户的详细信息,需使用apt-get提前安装;

实例:

$ who mom likes
zhangwang ttys003  May  8 14:58 
$ who am i
zhangwang ttys003  May  8 14:58 
# pts/0 中 pts(mac ttys) 表示伪终端,pts/0(ttys003) 后面那个数字就表示打开的伪终端序号
$ sudo apt-get finger
$ finger
# 会列出当前用户的信息
Login      Name        Tty      Idle  Login Time   Office     Office Phone
zhangwang  zhangwang   pts/0          May  4 21:04 (125.34.199.251)

老大用户root

一般通过上面的操作会发现我们当前登录的用户并非root,在Linux中,老大root 账户拥有整个系统至高无上的权利,它可以操作系统中所有的对象。在某些发行版中,这个用户并不显式存在,不过如果其它的用户具有使用sudo的权利(后文会叙述如何获取),通过sudo 命令也可以达到用root账号操作的效果。创建用户就是一个需要sudo权限的命令。

创建用户adduser

此命令的使用可参看以下实例:

zhangwang@Ubuntu:~$ sudo adduser student
[sudo] password for zhangwang: 
Adding user `student' ...
Adding new group `student' (1002) ...
Adding new user `student' (1002) with group `student' ...
Creating home directory `/home/student' ...
Copying files from `/etc/skel' ...
Enter new UNIX password: 
Retype new UNIX password: 
passwd: password updated successfully
Changing the user information for student
Enter the new value, or press ENTER for the default
    Full Name []: Udacity Linux Student
    Room Number []: 
    Work Phone []: 
    Home Phone []: 
    Other []: 
Is the information correct? [Y/n] Y
# finger 用户管理用户
zhangwang@Ubuntu:~$ finger student
Login: student                    Name: Udacity Linux Student
Directory: /home/student                Shell: /bin/bash
Never logged in.
No mail.
No Plan.

说完了如何添加用户,再说说如何切换用户。
切换用户相关命令:

  • su <user>:切换到用户user,执行时需要输入目标用户的密码;

  • su - <user>:切换用户,同时环境变量也会跟着改变成目标用户的环境变量

  • su -l lilei:切换登录用户;

有时候我们也会看到添加用户使用的命令是useradd,而非adduser下面说说二者的区别:

  • sudo adduser lilei:新建一个叫做lilei的用户,添加用户到系统,同时也会默认为新用户创建 home目录:

  • sudo useradd:只创建用户,创建完了需要用 passwd lilei 去设置新用户的密码;

用户组,给用户添加组织

在 Linux 里面每个用户都有一个归属(用户组),用户组简单地理解就是一组用户的集合,它们共享一些资源和权限,同时拥有私有资源。

查看用户属于那些组(groups):
使用示例:

~ groups zhangwang
# staff everyone localaccounts _appserverusr admin...

关于用户组我们需要注意:

  • 每次新建用户如果不指定用户组的话,默认会自动创建一个与用户名相同的用户组;

  • 默认情况下在 sudo 用户组里的可以使用 sudo 命令获得 root 权限。

  • 使用cat /etc/group | sort命令查看某组包含那些成员:/etc/group文件中分行显示了用户组(Group)、用户组口令、GID 及该用户组所包含的用户(User),格式如下:

group_name:password:GID:user_list
group:*:16:
interactusers:*:51:
kmem:*:2:root
localaccounts:*:61:
# *表示密码不可见
mail:*:6:_teamsserver

为用户添加组织:
不同的组对不同的文件可能具有不同的操作权限,比如说通过上述命令新建的用户默认是没有使用sudo的权限的,我们可以使用usermod命令把它加入sudo组用以具备相应的权限。
方法如下:

$ sudo usermod -G sudo student
$ groups lilei
# lilei:lilei sudo

删除用户的方法

删除用户也是一个需要管理员权限的命令,使用方法如下:

  • sudo deluser student --remove-home:删除用户及用户相关文件;

  • 直接的deluser会删除该用户,但是不会删除用户相关文件;

文件权限管理

使用Linux的过程中,查看修改文件是我们常做的事情之一。但是正如前文所说,文件是有所有权概念的,对同一个文件并非所有用户都对其有一样的权限。

前面我们提到使用ls命令可以查看文件,ls后还可以带各种参数以实现不同的查看效果,具体如下:

  • ls -l:查看文件及其权限;

  • ls -A:显示隐藏文件(包括以.开头的文件);(a->all)

  • ls -Al:显示隐藏文件及其权限;

  • ls -dl<查看一文件的完整属性>:(d->detail)

  • ls -AsSh:显示所有文件大小,并以普通人类能看懂的方式呈现(小 s 为显示文件大小,大 S 为按文件大小排序);

示例如下(注:命令行中的Python是我所操作的当前目录的名称):

➜  Python ls -l
total 0
drwxr-xr-x   9 zhangwang  staff  306  5 11 19:06 Bucketlist
drwxr-xr-x  10 zhangwang  staff  340  5  4 13:58 TofelWePrograme
drwxr-xr-x  14 zhangwang  staff  476  4 25 16:41 alien_invasion
drwxr-xr-x  12 zhangwang  staff  408  5 25 11:13 flasky
drwxr-xr-x  10 zhangwang  staff  340  4 26 19:06 learning_log
# 文件类型和权限 链接数 所有者 用户所在组 大小 最后修改时间 文件名称

上面的代码中,最让人疑惑的可能就是文件类型和权限这一项了,我们来逐一解释。

文件类型

说到文件,不得不提文件类型,Linux中的文件不同于Windows中的文件,在Linux 里面一切皆文件,主要文件类型有以下几种:

  • 普通文件:一般是用一些相关的应用程序创建的(如图像工具、文档工具、归档工具... 或 cp工具等),这类文件的删除方式是用rm 命令,而创建使用touch命令,用符号-表示;

  • 目录:目录在Linux是一个比较特殊的文件,用字符d表示,删除用rm 或rmdir命令;

  • 块设备文件:存在于/dev目录下,如硬盘,光驱等设备,用字符d表示;

  • 设备文件:( /dev 目录下有各种设备文件,大都跟具体的硬件设备相关),如猫的串口设备,用字符c表示;

  • socket文件;用字符s表示,比如启动MySQL服务器时,产生的mysql.sock的文件;

  • pipe 管道文件:可以实现两个程序(可以从不同机器上telnet)实时交互,用字符p表示;

  • 链接文件:软链接等同于 Windows 上的快捷方式;用字符l表示;

软硬链接文件的共同点和区别:无论是修改软链接,硬链接生成的文件还是直接修改源文件,相应的文件都会改变,但是如果删除了源文件,硬链接生成的文件依旧存在而软链接生成的文件就不再有效了。

文件权限

上面的代码示例中,另一个比较让人疑惑的是drwxr-xr-x这样的语句,这段语句表明了文件的权限。Linux中文件权限主要由以下几种:

  • 读权限:可以使用 cat <file name> 之类的命令来读取某个文件的内容;

  • 写权限,表示你可以编辑和修改某个文件;

  • 执行权限,通常指可以运行的二进制程序文件或者脚本文件(Linux 上不是通过文件后缀名来区分文件的类型);

  • 所有者权限,所属用户组权限,是指你所在的用户组中的所有其它用户对于该文件的权限

一个目录同时具有读权限和执行权限才可以打开并查看内部文件,而一个目录要有写权限才允许在其中创建其它文件,这是因为目录文件实际保存着该目录里面的文件的列表等信息。

可用下图加强对文件权限的理解:
图释Linux文件权限

修改文件权限的方法

从上图中可以看出,每个文件有三组权限(拥有者,所属用户组,其他用户,这个顺序是一定的),修改权限的命令是chmod,修改文件权限的方法有两种,所示:

# 用数字的形式表示,数字的来源及计算方法见下图,数字的意义见下图
$ chmod 700 iphone6 # 让用户对iPhone6文件具备读写权限,所在组和其它用户都没有读写权限
# 用字母的形式表示,g、o 还有 u 分别表示 group、others 和 user,+ 和 - 分别表示增加和去掉相应的权限
$ chmod go-rw iphone6 # 让用户所属用户组及其它用户对iPhone6这个文件不再有读写权限

文件权限的数字计算方式

更改文件所有者chown

上面描述文件权限时,都是以自己,所在组,其它三个级别来描述的,那如果你登录的当前账户不是某个文件的所有者,你又不想让这个文件对所有用户开发你想用到的权限,该怎么办呢。还记得前面我们说过老大root用户对所有的文件具有绝对的支配权,我们可以利用这个账号把一个文件过继给另外一个用户(更改文件的所有者)以方便该用户对该文件的操作,使用方法如下:

# sudo 表示已root的权限执行,下面语句的意思是把/etc/apt文件夹下面的sources.list的所有权转让给用户zhangwang
$ sudo chown zhangwang /etc/apt/sources.list 
$ sudo chmod 700 /etc/apt/sources.list

对文件的基本操作

现在我们有能力获得对某文件的操作能力了,接下来看看Linux下对文件进行简单操作的命令。

创建

touch:

  • 主要作用是来更改已有文件的时间戳的(比如,最近访问时间,最近修改时间);

  • 在不加任何参数的情况下,只指定一个文件名,则可以创建一个指定文件名的空白普通文件(不会覆盖已有同名文件)

mkdir:

  • 新建空目录$ mkdir mydir

  • 新建多级目录$ mkdir -p father/son/grandson

复制移动

cp:

  • $ cp test father/son/grandson:复制test文件到father/son/grandson;

  • $ cp -r father family:递归复制目录
    mv:

  • $ mv file1 Documents:移动文件files到Documents目录

  • $ mv file1 myfile:将文件“ file1 ”重命名为“ myfile ”

删除

rm:

  • $ rm test

  • $ rm -f test:删除只读文件,强制删除

  • $ rm -r family:删除目录(递归删除其中的子文件)

其它操作

  • rename:批量重命名,需要用到正则表达式

代码示例

# 使用通配符批量创建 5 个文件:
$ touch file{1..5}.txt

# 批量将这 5 个后缀为 .txt 的文本文件重命名为以 .c 为后缀的文件:
$ rename 's/\.txt/\.c/' *.txt

# 批量将这 5 个文件,文件名改为大写:
$ rename 'y/a-z/A-Z/' *.c

查看文件

cat:打印文件内容到标准输出(终端)(正序);

  • cat -n passwd:显示行号,此外还有以下命令

tac:打印文件内容到标准输出(终端)(逆序);

标准输入输出:当我们执行一个 shell 命令行时通常会自动打开三个标准文件,即标准输入文件(stdin),默认对应终端的键盘、标准输出文件(stdout)和标准错误输出文件(stderr),后两个文件都对应被重定向到终端的屏幕,以便我们能直接看到输出内容。进程将从标准输入文件中得到输入数据,将正常输出数据输出到标准输出文件,而将错误信息送到标准错误文件中。

cat,tac参数的说明如下:

-b : 指定添加行号的方式,主要有两种:
    -b a:表示无论是否为空行,同样列出行号("cat -n"就是这种方式)
    -b t:只列出非空行的编号并列出(默认为这种方式)
-n : 设置行号的样式,主要有三种:
    -n ln:在行号字段最左端显示
    -n rn:在行号字段最右边显示,且不加 0
    -n rz:在行号字段最右边显示,且加 0
-w : 行号字段占用的位数(默认为 6 位)

more:比较简单,只能向一个方向滚动,查看文件:打开后默认只显示一屏内容,终端底部显示当前阅读的进度。可以使用 Enter 键向下滚动一行,使用 Space 键向下滚动一屏,按下 h 显示帮助,q 退出。

less:less 基于 more 和 vi查看文件,使用基本和 more 一致

head:查看文件的头几行(默认10行)
tail:查看文件的尾几行(默认10行)

  • $ tail -n 1 /etc/passwd 查看固定行数

file:查看文件类型$ file /bin/ls

Linux 的目录结构

前面多次提到了类似/dev这样的目录,也提到了目录文件d,不知道你对目录有没有也产生好奇,Linux的目录也是Linux系统中比较重要的一块,不过首先我们得区分Linux的目录和Window的目录的较大的区别:

不同之一体现在目录与存储介质(磁盘,内存,DVD 等)的关系上,Windows 一直是以存储介质为主的,主要以盘符(C 盘,D 盘...)及分区来实现文件管理,然后之下才是目录,目录就显得不是那么重要,除系统文件之外的用户文件放在任何地方任何目录也是没有多大关系。

然而 UNIX/Linux 恰好相反,UNIX 是以目录为主的,Linux 也继承了这一优良特性。 Linux 以树形目录结构的形式来构建整个系统,可以理解为树形目录是一个用户可操作系统的骨架。虽然本质上无论是目录结构还是操作系统内核都是存储在磁盘上的,但从逻辑上来说 Linux 的磁盘是“挂在”(挂载在)目录上的,每一个目录不仅能使用本地磁盘分区的文件系统,也可以使用网络上的文件系统

简言之,Windows的目录挂载在磁盘下,而Linux磁盘挂载在目录下,使用Mac的童鞋们,看了这段话是不是突然明白了为什么Mac上安装第三方软件时,会出现盘符。

初接触Linux时,我们很容易被其看似复杂的文件系统弄得晕头转向,其实在掌握了一定的规律后,Linux的目录结构是比Window简单的(你现在能说清windows系统盘各文件夹的作用不),Linux的大部分目录结构是依据FHS标准(英文:Filesystem Hierarchy Standard 中文:文件系统层次结构标准)规定好的,

多数 Linux 版本采用这种文件组织形式,FHS 定义了系统中每个区域的用途、所需要的最小构成的文件和目录同时还给出了例外处理与矛盾处理。

FHS包含两层规范:

  • 第一层是, / 下面的各个目录应该要放什么文件数据,例如 /etc 应该放置设置文件,/bin/sbin 则应该放置可执行文件等等。

  • 第二层则是针对 /usr/var 这两个目录的子目录来定义。例如 /var/log 放置系统登录文件,/usr/share 放置共享数据等等。

这里有个有用的命令:tree(需要先安装),可以查看某个目录的子目录的结构,这个命令还可以限制目录的展示层级,通过man tree你可以获知如何进行具体的操作。

FHS 是根据以往无数 Linux 用户和开发者的经验总结出来的,并且会维持更新,网上有很多结束FHS的文章,如果感兴趣 可以搜索看看。

我们回顾一下关于目录的一些常用相关命令:

  • ..:表示上一级目录

  • cd:切换目录,后面可以是相对目录,也可以是绝对目录,如$ cd /usr/local/bin

  • pwa:查看当前所在目录

查看目录的容量du

使用du命令可以查看目录的容量,配合以下参数可以实现更多效果。
参数:

  • -d:指定查看目录的深度``

# 只查看1级目录的信息
$ du -h -d 0 ~
# 查看2级
$ du -h -d 1 ~

du -h #同--human-readable 以K,M,G为单位,提高信息的可读性。
du -a #同--all 显示目录中所有文件的大小。
du -s #同--summarize 仅显示总计,只列出最后加总的值。

# 只查看特定目录
➜  ~ du -h -d 1 /Users/zhangwang/Git
  0B    /Users/zhangwang/Git/.idea
654M    /Users/zhangwang/Git/backUp
 80K    /Users/zhangwang/Git/Canvas
235M    /Users/zhangwang/Git/CoderWood
273M    /Users/zhangwang/Git/frontend
 64K    /Users/zhangwang/Git/git_hug
217M    /Users/zhangwang/Git/mongodb
3.6M    /Users/zhangwang/Git/node
304M    /Users/zhangwang/Git/proJourn

Linux的磁盘管理

在Linux下磁盘是挂载在目录下的,前文大致聊了目录,接下来我们简单说说磁盘管理,前面刚刚说完如何查看目录容量,我们先卡如何查看磁盘的容量。

查看磁盘容量df

使用df命令可以查看磁盘的容量
使用方法可见下例:

➜  ~ df
Filesystem    512-blocks      Used Available Capacity iused      ifree %iused  Mounted on
/dev/disk1     234586112 194476264  39597848    84% 2414807 4292552472    0%   /
devfs                370       370         0   100%     640          0  100%   /dev
map -hosts             0         0         0   100%       0          0  100%   /net
map auto_home          0         0         0   100%       0          0  100%   /home
/dev/disk2s1      732080    461176    270904    63%    4684 4294962595    0%   /Volumes/微信web开发者工具
# 以更友善的方式展示
$ df -h

上面这条命令是在Mac上执行的,有没有发现微信web开发者工具的安装盘也是一个磁盘。当然这类磁盘都不是真实的物理磁盘,而是虚拟磁盘,下面我们看看如何创建虚拟磁盘:

创建虚拟磁盘dd

说明:

dd命令用于转换和复制文件,不过它的复制不同于cp。之前提到过关于 Linux 的很重要的一点,一切即文件,在 Linux 上,硬件的设备驱动(如硬盘)和特殊设备文件(如/dev/zero和/dev/random)都像普通文件一样,只要在各自的驱动程序中实现了对应的功能,dd 也可以读取自和/或写入到这些文件。这样,dd也可以用在备份硬件的引导扇区、获取一定数量的随机数据或者空数据等任务中。dd程序也可以在复制时处理数据,例如转换字节序、或在 ASCII 与 EBCDIC 编码间互换。

语句格式:选项=值
dd默认从标准输入中读取,并写入到标准输出中,但输入输出也可以用选项if(input file,输入文件)和of(output file,输出文件)改变。

bb复制的基本使用方法如下:

$ dd if=/dev/stdin of=/dev/stdout bs=10 count=1
# 将输出的英文字符转换为大写再写入文件
$ dd if=/dev/stdin of=test bs=10 count=1 conv=ucase
  • bs(block size)用于指定块大小(缺省单位为 Byte,也可为其指定如'K','M','G'等单位),

  • count用于指定块数量。

  • 超过bs的多余输入将被截取并保留在标准输入。

使用dd命令创建虚拟镜像文件

# 从/dev/zero设备创建一个容量为 256M 的空文件virtual.img:
$ dd if=/dev/zero of=virtual.img bs=1M count=256
$ du -h virtual.img

使用mkfs命令格式化磁盘

# 输入 sudo mkfs 然后按下Tab键,你可以看到很多个以 mkfs 为前缀的命令,代表不同的文件系统格式
# 格式化virtual.img为ext4格式
$ sudo mkfs.ext4 virtual.img

使用 mount 命令挂载磁盘到目录树

用户在 Linux/UNIX 的机器上打开一个文件以前,包含该文件的文件系统必须先进行挂载的动作,此时用户要对该文件系统执行 mount 的指令以进行挂载。
Linux/UNIX 文件系统可以对应一个文件而不一定要是硬件设备,所以可以挂载一个包含文件系统的文件到目录树。

对Mac安装软件方式的原因理解又进了一步了。

具体使用方法如下:

# 查看下主机已经挂载的文件系统,每一行代表一个设备或虚拟设备格式[设备名]on[挂载点]:
$ sudo mount
➜  ~ sudo mount
Password:
/dev/disk1 on / (hfs, local, journaled)
devfs on /dev (devfs, local, nobrowse)
map -hosts on /net (autofs, nosuid, automounted, nobrowse)
map auto_home on /home (autofs, automounted, nobrowse)
/dev/disk2s1 on /Volumes/微信web开发者工具 (hfs, local, nodev, nosuid, read-only, noowners, quarantine, mounted by zhangwang)

# 挂载文件到目录树mount [-o [操作选项]] [-t 文件系统类型] [-w|--rw|--ro] [文件系统源] [挂载点]
# 类型可省略,很多时候会自动识别
$ mount -o loop -t ext4 virtual.img /mnt 
# 以只读方式挂载
$ mount -o loop --ro virtual.img /mnt

使用 fdisk 为磁盘分区

磁盘分区大家肯定也很熟悉,Linux下对磁盘分区的方法也很简单,示例如下

# 查看硬盘分区表信息
$ sudo fdisk -l

# 进入磁盘分区模式
$ sudo fdisk virtual.img

到这里,我们初步初步了解了Linux的核心系统,接下来我们对Linux下的一些常用操作进行叙述。

Linux的常用操作

很多人装完系统后第一件事就是装软件,应用部分我们也从软件的安装说起,还是以Ubuntu为例介绍软件的安装和卸载方法:

软件的安装和卸载

Linux上软件的安装有四种形式

  • 在线安装

  • 从磁盘安装deb安装包

  • 从二进制软件包安装

  • 从源代码安装

在线安装

在线安装命令很简洁,我们先看使用方式,然后叙述每一步的意义:

$ sudo apt-get install cowsay
# 如果你在安装一个软件之后,无法立即使用Tab键补全这可命令,使用下述命令刷新
$ source ~/.zshrc

那么安装的过程究竟发生了什么:

  • 在本地的一个数据库中搜索关于 cowsay 软件的相关信息

  • 根据这些信息在相关的服务器上下载软件安装

  • 安装某个软件时,如果该软件有其它依赖程序,系统会为我们自动安装所以来的程序;

  • 如果本地的数据库不够新,可能就会发生搜索不到的情况,这时候需要我们更新本地的数据库,使用命令sudo apt-get update可执行更新;

  • 软件源镜像服务器可能会有多个,有时候某些特定的软件需要我们添加特定的源;

apt-get描述

很可能apt-get会是很长一段时间内,你使用的最多的命令,我们先对其进行详细的描述
作用:用于处理 apt包的公用程序集,我们可以用它来在线安装、卸载和升级软件包

apt-get命令后可以接不同的工具实现不同的效果,描述如下:
工具 说明

  • install 其后加上软件包名,用于安装一个软件包

  • update 从软件源镜像服务器上下载/更新用于更新本地软件源的软件包列表

  • upgrade 升级本地可更新的全部软件包,但存在依赖问题时将不会升级,通常会在更新之前执行一次update

  • dist-upgrade 解决依赖关系并升级(存在一定危险性)

  • remove 移除已安装的软件包,包括与被移除软件包有依赖关系的软件包,但不包含软件包的配置文件

  • autoremove 移除之前被其他软件包依赖,但现在不再被使用的软件包

  • purge 与remove相同,但会完全移除软件包,包含其配置文件

  • clean 移除下载到本地的已经安装的软件包,默认保存在/var/cache/apt/archives/

  • autoclean 移除已安装的软件的旧版本软件包

apt-get后还可以更一些常见的参数,对这些参数的描述如下:

  • -y 自动回应是否安装软件包的选项,在一些自动化安装脚本中使用这个参数将十分有用

  • -s 模拟安装

  • -q 静默安装方式,指定多个q或者-q=#,#表示数字,用于设定静默级别,这在你不想要在安装软件包时屏幕输出过多时很有用

  • -f 修复损坏的依赖关系

  • -d 只下载不安装

  • --reinstall 重新安装已经安装但可能存在问题的软件包

  • --install-suggests 同时安装APT给出的建议安装的软件包

实例

# 重装
$ sudo apt-get --reinstall install w3m
# 更新软件源
$ sudo apt-get update
# 升级没有依赖问题的软件包
$ sudo apt-get upgrade
# 升级并解决依赖关系
$ sudo apt-get dist-upgrade
# 卸载
$ sudo apt-get remove w3m

# 不保留配置文件的移除
$ sudo apt-get purge w3m
# 或者 sudo apt-get --purge remove
# 移除不再需要的被依赖的软件包
$ sudo apt-get autoremove
使用apt-cache 命令实现软件搜索

sudo apt-cache search softname1 softname2 softname3……

apt-cache 命令则是针对本地数据进行相关操作的工具,search 顾名思义在本地的数据库中寻找有关 softname1 softname2 …… 相关软件的信息

使用dpkg从本地磁盘安装deb软件包

有时候我们也需要下载一些安装包安装,比如你想在Ubuntu下使用webstorm,就可以在其官网上下载响应的deb软件包,使用dpkg命令来安装

dpkg的常见参数

  • -i 安装指定deb包

  • -R 后面加上目录名,用于安装该目录下的所有deb安装包

  • -r remove,移除某个已安装的软件包

  • -I 显示deb包文件的信息

  • -s 显示已安装软件的信息

  • -S 搜索已安装的软件包
    -L 显示已安装软件包的目录信息

使用实例

$ cp /var/cache/apt/archives/emacs24_24.3+1-4ubuntu1_amd64.deb ~
# 安装之前参看deb包的信息
$ sudo dpkg -I emacs24_24.3+1-4ubuntu1_amd64.deb
# dpkg并不能为你解决依赖关系
$ sudo dpkg -i emacs24_24.3+1-4ubuntu1_amd64.deb
# 修复依赖关系的安装
$ sudo apt-get -f install

# 查看已安装软件包的安装目录
$ sudo dpkg -L emacs

从二进制安装

二进制包的安装比较简单,我们需要做的只是将从网络上下载的二进制包解压后放到合适的目录,然后将包含可执行的主程序文件的目录添加进PATH环境变量即可,如果你不知道该放到什么位置,请重新复习第四节关于 Linux 目录结构的内容。

说到了环境变量,接下来我们仔细聊聊shell下的变量,并掌握添加环境变量的方法。

Linux变量

或许你也有过这样的经历,想通过命令行启动某些操作,比如说使用VSCode时希望通过 在命令行中通过code ./project命令打开相应的文件夹。

各编程语言中都有变量的概念,Shell中的变量也基本如此,变量有如下特点

  • 不同类型(但不用专门指定类型名)

  • 可以参与运算

  • 有作用域限定

我们看看在bash中添加变量的方法:

#使用 declare 命令创建一个变量名为 tmp 的变量
$ declare tmp:

# 使用 = 号赋值运算符,将变量 tmp 赋值为 God
$ tmp=God

# 读取变量的值:使用 echo 命令和 $ 符号($ 符号用于表示引用一个变量的值)
$ echo $tmp
# 将输出God
➜  ~ 

Shell中的变量类型

1.自定义变量:当前 Shell 进程私有用户自定义变量,如上面我们创建的 tmp 变量,只在当前 Shell 中有效。

    • 相关命令:set:显示当前 Shell 所有变量,包括其内建环境变量(与 Shell 外观等相关),用户自定义变量及导出的环境变量。

    1. Shell 本身内建的变量

      • 相关命令:env:显示与当前用户相关的环境变量,还可以让命令在指定环境中运行。

    2. 从自定义变量导出的环境变量。

      • 相关命令:export :显示从 Shell 中导出成环境变量的变量,也能通过它将自定义变量导出为环境变量。

      • export temp导出变量temp为环境变量

      • 通常我们习惯将环境变量名设置为大写;

    在所有的 UNIX 和类 UNIX 系统中,每个进程都有其各自的环境变量设置,且默认情况下,当一个进程被创建时,处理创建过程中明确指定的话,它将继承其父进程的绝大部分环境设置。Shell 程序也作为一个进程运行在操作系统之上,而我们在 Shell 中运行的大部分命令都将以 Shell 的子进程的方式运行。

    环境变量,可以简单地理解成如果某变量在当前进程的子进程有效则为环境变量,否则不是。(在Shell中输入zsh或者bash其实就是创建了一个子shell)。

    我们也可以安装生存周期划分Shell变量:

    • 永久的:需要修改配置文件,变量永久生效;

    • 临时的:使用 export 命令行声明即可,变量在关闭 shell 时失效。

    永久变量涉及到两个重要文件 /etc/bashrc(有的 Linux 没有这个文件) 和 /etc/profile ,它们分别存放的是 shell 变量和环境变量。 .profile(不是/etc/profile) 只对当前用户永久生效。而写在 /etc/profile 里面的是对所有用户永久生效,所以如果想要添加一个永久生效的环境变量,只需要打开 /etc/profile,在最后加上你想添加的环境变量就好啦。

    添加命令到环境变量

    添加命令到环境变量几乎是每个使用Linux系统的人都会进行的操作:它实现了在 Shell 中输入一个命令,能通过环境变量 PATH 来进行搜索并执行命令,PATH 里面就保存了 Shell 中执行的命令的搜索路径。

    添加自定义路径到"PATH"环境变量的具体方法如下:
    一次性的:

    # 这里一定要使用绝对路径
    $ PATH=$PATH:/home/zhangwang/mybin
    # 给 PATH 环境变量追加了一个路径,它也只是在当前 Shell 有效,我一旦退出终端,再打开就会发现又失效了。

    通过上述设置,就可以执行mybin目录下的所有命令了。

    永久的:
    想要永久的添加这类环境变量可以用接下来额方法,每个用户的 home 目录中有一个 Shell 每次启动时会默认执行一个配置脚本,以初始化环境,包括添加一些用户自定义环境变量等等。zsh 的配置文件是 .zshrc,相应 Bash 的配置文件为 .bashrc 。它们在 etc 下还都有一个或多个全局的配置文件,不过我们一般只修改用户目录下的配置文件。

    # 可以简单地使用下面命令直接添加内容到 .zshrc 中
    $ echo "PATH=$PATH:/home/shiyanlou/mybin" >> .zshrc

    上述命令中 >> 表示将标准输出以追加的方式重定向到一个文件中
    当然,你用vim等编辑器直接打开对应文件也是可以实现类似的操作的。

    修改和删除已有的变量

    有如下几种方式:

    • ${变量名#匹配字串}: 从头向后开始匹配,删除符合匹配字串的最短数据

    • ${变量名##匹配字串}: 从头向后开始匹配,删除符合匹配字串的最长数据

    • ${变量名%匹配字串}: 从尾向前开始匹配,删除符合匹配字串的最短数据

    • ${变量名%%匹配字串}: 从尾向前开始匹配,删除符合匹配字串的最长数据

    • ${变量名/旧的字串/新的字串}:将符合旧字串的第一个字串替换为新的字串

    • ${变量名//旧的字串/新的字串}: 将符合旧字串的全部字串替换为新的字串

    删除删除

    # 删除变量temp
    $ unset temp

    让环境变量理解生效

    有时候修改了环境变量并未马上生效可用下面这种方法使其马上生效:

    # 在修改了.zshrc文件后
    $ source .zshrc
    # source有一个别名叫做.因此可以用下面的方法使得理解生效(第一个点后面有一个空格,且路径需要为绝对路径或者相对路径)
    $ . ./.zshrc

    文件的打包和压缩

    文件的打包和压缩是另一种我们可能会常做的操作,比如说你想在服务器上部署一个wiki系统,下载了dokuwiki的压缩文件夹,这时候就需要解压啦。

    常见压缩格式

    • *.zip zip 程序打包压缩的文件

    • *.rar rar 程序压缩的文件

    • *.7z 7zip 程序压缩的文件

    • *.tar tar 程序打包,未压缩的文件

    • *.gz gzip 程序(GNU zip)压缩的文件

    • *.xz xz 程序压缩的文件

    • *.bz2 bzip2 程序压缩的文件

    • *.tar.gz tar 打包,gzip 程序压缩的文件

    • *.tar.xz tar 打包,xz 程序压缩的文件

    • *tar.bz2 tar 打包,bzip2 程序压缩的文件

    • *.tar.7z tar 打包,7z 程序压缩的文件

    使用zip压缩打包程序

    # 代码引用自实验楼相关课程
    $ zip -r -q -o shiyanlou.zip /home/shiyanlou
    # 查看文件大小
    $ du -h shiyanlou.zip
    $ file shiyanlou.zip
    # 设置不同压缩等级
    $ zip -r -9 -q -o shiyanlou_9.zip /home/shiyanlou -x ~/*.zip
    $ zip -r -1 -q -o shiyanlou_1.zip /home/shiyanlou -x ~/*.zip
    $ du -h -d 0 *.zip ~ | sort
    # 创建加密
    $ zip -r -e -o shiyanlou_encryption.zip /home/shiyanlou
    # 解决windows和linux对换行的不同处理问题
    $ zip -r -l -o shiyanlou.zip /home/shiyanlou

    参数说明:

    • -r:表示递归打包包含子目录的全部内容

    • -q:表示为安静模式,即不向屏幕输出信息

    • -o:表示输出文件,需在其后紧跟打包输出文件名

    • -[1-9]:设置压缩等级,1 表示最快压缩但体积大,9 表示体积最小但耗时最久。

    • -x:排除我们上一次创建的 zip 文件,否则又会被打包进这一次的压缩文件中

    • -e:创建加密压缩包

    • -l:将 LF(换行) 转换为 CR+LF(windows 回车加换行)

    使用unzip命令解压缩zip文件

    # 基本使用
    $ unzip shiyanlou.zip
    # 静默且指定解压目录,目录不存在会自动创建
    $ unzip -q shiyanlou.zip -d ziptest
    # 使用 -O(英文字母,大写 o)参数指定编码类型
    $ unzip -O GBK 中文压缩文件.zip

    rar打包压缩命令

    # 安装
    $ sudo apt-get update
    $ sudo apt-get install rar unrar
    
    # 基本使用,a(没有`-`) 参数添加一个目录 ~ 到一个归档文件中,如果该文件不存在就会自动创建
    $ rar a shiyanlou.rar .
    
    # 从指定压缩包文件中删除某个文件:
    $ rar d shiyanlou.rar .zshrc
    
    # 查看不解压文件:
    $ rar l shiyanlou.rar
    
    # 全路径解压:
    $ rar l shiyanlou.rar
    
    # 去掉路径解压:
    $ mkdir tmp
    $ unrar e shiyanlou.rar tmp/

    tar的使用

    说明:

    tar 原本只是一个打包工具,只是同时还是实现了对 7z、gzip、xz、bzip2 等工具的支持,这些压缩工具本身只能实现对文件或目录(单独压缩目录中的文件)的压缩,没有实现对文件的打包压缩,所以我们也无需再单独去学习其他几个工具,tar 的解压和压缩都是同一个命令,只需参数不同,使用比较方便。

    # 创建一个 tar 包:
    $ tar -cf shiyanlou.tar ~
    # 解压
    $ mkdir tardir
    $ tar -xf shiyanlou.tar -C tardir
    # 查看不解包文件 -t 参数
    $ tar -tf shiyanlou.tar
    # 创建不同格式压缩文件(gzip)
    $ tar -czf shiyanlou.tar.gz ~
    #解压gzip
    $ tar -xzf shiyanlou.tar.gz
    • -c:创建一个 tar 包文件

    • -f:指定创建的文件名,文件名必须写在-f参数后

    • -v:以可视的的方式输出打包的文件

    • -P:保留绝对路径符(默认不保留,防止解压到根目录)

    • -x:解压

    • -C:解压到指定路径的已存在目录

    • -z:使用gzip压缩

    其它压缩格式

    • *.tar.gz:-z

    • *.tar.xz:-J

    • *.tar.bz2:-j

    获取帮助

    Linux下的命令非常多,遇到不熟悉的命令的情况很常见,不过在Linux获取相应的帮助的方法也很简单,主要有以下几种方法:

    help

    help 命令是用于显示 shell 内建命令的简要帮助信息。帮助信息中显示有该命令的简要说明以及一些参数的使用以及说明。

    使用:help exit

    man

    man 没有内建与外部命令的区分,因为 man 工具是显示系统手册页中的内容,也就是一本电子版的字典,这些内容大多数都是对命令的解释信息,还有一些相关的描述。通过查看系统文档中的 man 也可以得到程序的更多相关信息和 Linux的更多特性。

    使用:man cowsay

    info

    得到的信息比 man 还要多,info 来自自由软件基金会的 GNU 项目,是 GNU 的超文本帮助系统,能够更完整的显示出 GNU 信息。
    man 和 info 就像两个集合,它们有一个交集部分,但与 man 相比,info 工具可显示更完整的 GNU 工具信息。若 man 页包含的某个工具的概要信息在 info 中也有介绍,那么 man 页中会有“请参考 info 页更详细内容”的字样。

    使用:info ls

    添加计划任务

    crontab 命令常见于 Unix 和类 Unix 的操作系统之中,用于设置周期性被执行的指令。该命令从输入设备读取指令,并将其存放于 crontab 文件中,以供之后读取和执行。通常,crontab 储存的指令被守护进程激活,crond 为其守护进程,crond 常常在后台运行,每一分钟会检查一次是否有预定的作业需要执行。

    通过 crontab 命令,我们可以在固定的间隔时间执行指定的系统指令或 shell script 脚本。时间间隔的单位可以是分钟、小时、日、月、周的任意组合。比如我们需要每天半夜两点钟自动在线更新数据源,用这个命令进行相关设置就可以实现啦。

    crontab命令使用步骤

    1. 启动rsyslog方便查看日志信息:sudo service rsyslog start;

    2. 启动crontabsudo cron -f &;

    3. 添加任务:crontab -e,选择合适的编辑器,这里选择1,最后一排我们可以看到计划任务的格式# m h dom mon dow command;(分 时 日 月 周 命令)

    4. 在文档最后一排添加如下命令:*/1 * * * * touch /home/shiyanlou/$(date +\%Y\%m\%d\%H\%M\%S)(每分钟添加一个以当前时间日期命名的空白文件)

    5. 使用crontab -l,查看添加了那些任务;

    6. 确定我们的 cron 是否成功的在后台启动,方式1:ps aux | grep cronpgrep cron;

    7. 在日志系统中查看信息反馈:sudo tail -f /var/log/syslog;

    8. 删除任务:crontab -r;

    9. 每个用户使用 crontab -e 添加计划任务,都会在 /var/spool/cron/crontabs 中添加一个该用户自己的任务文档,这样目的是为了隔离。以 sudo 权限编辑 /etc/crontab 文件就可以添加系统级别的定时任务;

    crontab -e 表示为当前用户添加计划任务
    sudo crontab -e 表示为root用户添加计划任务
    1. cron 服务监测时间最小单位是分钟,所以 cron 会每分钟去读取一次 /etc/crontab 与 /var/spool/cron/crontabs 里面的內容。

    /etc/cron.daily,目录下的脚本会每天执行一次,在每天的6点25分时运行;

    /etc/cron.hourly,目录下的脚本会每个小时执行一次,在每小时的17分钟时运行;
    /etc/cron.mouthly,目录下的脚本会每月执行一次,在每月1号的6点52分时运行;
    /etc/cron.weekly,目录下的脚本会每周执行一次,在每周第七天的6点47分时运行;

    命令执行顺序的控制

    简单的顺序执行可以安装以下方法,以;分隔众多命令,shell会自动执行:

    $ sudo apt-get update;sudo apt-get install some-tool;some-tool

    不过我们也可以有选择的执行命令:
    && 和 ||的使用:

    • &&:表示当前一条命令满足条件时执行后面的语句:

    $ which cowsay>/dev/null && cowsay -f head-in ohch~
    • ||:当前的命令不满足条件时执行的后面的语句

    $ which cowsay>/dev/null || echo "cowsay has not been install, please run 'sudo apt-get install cowsay' to install"
    • 二者一起使用:

    $ which cowsay>/dev/null && echo "exist" || echo "not exist"

    注:使用$?可以获取上一个命令的返回值(成功为0,不成功为1),which命令在前文中有叙述;

    管道

    管道是一种通信机制,通常用于进程间的通信(也可通过socket进行网络通信),它表现出来的形式就是将前面每一个进程的输出(stdout)直接作为下一个进程的输入(stdin)。

    管道又分为匿名管道和具名管道。我们在使用一些过滤程序时经常会用到的就是匿名管道,在命令行中由|分隔符表示,|在前面的内容中我们已经多次使用到了。具名管道简单的说就是有名字的管道。

    # 获取etc文件下的详细信息,并以less的方式显示
    $ ls -al /etc | less

    Shell下的一些其它常用命令

    前面已经讲述了很多Shell下的常用命令,下面在列出一起其它常用的命令

    cut命令,打印每一行的某一字段

    # 打印/etc/passwd文件中以:为分隔符的第1个字段和第6个字段分别表示用户名和其家目录:
    $ cut /etc/passwd -d ':' -f 1,6
    
    # 前五个(包含第五个)
    $ cut /etc/passwd -c -5
    # 前五个之后的(包含第五个)
    $ cut /etc/passwd -c 5-
    # 第五个
    $ cut /etc/passwd -c 5
    # 2到5之间的(包含第五个)
    $ cut /etc/passwd -c 2-5
    • -d:用来定义分隔符,默认为tab键,一般与-f配合使用(如果分隔符是空格,必须是两个单引号之间确实有一个空格,是一个哦,不是支持多个)

    • -f:需要选取的字段,根据-d切分的字段集选取,下标从1开始

    • -s:表示不包括那些不含分隔符的行,用于去掉注释或者标题一类的信息

    • -c:以字符为单位进行分割,可以选取指定字符

    • -b:以字节为单位进行分割,可以选取指定字节,这些字节位置将忽略多字节字符边界(比如:汉字),除非同时指定了-n参数

    • -n:取消分割多字节字符,只能和-b参数配合使用,即如果字符的最后一个字节落在由-b参数列表指定的范围之内,则该字符将被选出,否则,该字符将被排除。

    grep 命令,在文本中或 stdin 中查找匹配字符串

    grep命令是很强大的,也是相当常用的一个命令,它结合正则表达式可以实现很复杂却很高效的匹配和查找
    查找,按照单引号匹配的内容进行搜索
    grep -n 'a' abc.txt:搜索abc.txt 文件中带a的内容
    - n:表示结果中带有行号。
    - i:忽略大小写
    -v: 取反 grep -v -n 'a' abc.txt:不带a

    使用格式

    grep [命令选项]... 用于匹配的表达式 [文件]...

    # 搜索/home/zhangwang目录下所有包含"zhangwang"的所有文本文件,并显示出现在文本中的行号:
    $ grep -rnI "zhangwang" ~

    wc 命令,简单小巧的计数工具

    wc 命令用于统计并输出一个文件中行、单词和字节的数目

    # 输出/etc/passwd文件的统计信息:
    $ wc /etc/passwd
    # 行数
    $ wc -l /etc/passwd
    # 单词数
    $ wc -w /etc/passwd
    # 字节数
    $ wc -c /etc/passwd
    # 字符数
    $ wc -m /etc/passwd
    # 最长行字节数
    $ wc -L /etc/passwd

    sort 排序命令

    将输入按照一定方式排序,然后再输出,它支持的排序有按字典排序,数字排序,按月份排序,随机排序,反转排序,指定特定字段进行排序等等。

    # 字典排序
    $ cat /etc/passswd | sort
    # 反转排序
    $ cat /etc/passwd | sort -r
    # 按特定字段排序
    $ cat /etc/passwd | sort -t':' -k 3
    # 按照数字排序就要加上-n参数
    $ cat /etc/passwd | sort -t':' -k 3 -n

    -t参数用于指定字段的分隔符,这里是以":"作为分隔符;-k 字段号用于指定对哪一个字段进行排序

    uniq 去重命令

    uniq命令可以用于过滤或者输出重复行。

    # 让history去掉命令后面的参数然后去掉重复的命令
    $ history | cut -c 8- | cut -d ' ' -f 1 | uniq
    # uniq命令只能去连续重复的行,不是全文去重,所以要达到预期效果,我们先排序:
    $ history | cut -c 8- | cut -d ' ' -f 1 | sort | uniq
    # 输出重复行
    # 输出重复过的行(重复的只输出一个)及重复次数
    $ history | cut -c 8- | cut -d ' ' -f 1 | sort | uniq -dc
    # 输出所有重复的行
    $ history | cut -c 8- | cut -d ' ' -f 1 | sort | uniq -D

    shell中的文本处理

    使用vim等编辑器当然可以进行文本处理,不过这里我们要讨论的是使用命令来进行文本处理

    tr命令删除

    使用方法
    tr [option]...SET1 [SET2]

    常用选项
    选项 说明

    • -d 删除和set1匹配的字符,注意不是全词匹配也不是按字符顺序匹配

    • -s 去除set1指定的在输入文本中连续并重复的字符

    实例:

    # 删除 "hello world" 中所有的'o','l','h'
    $ echo 'hello world' | tr -d 'olh'
    # 将"hello" 中的ll,去重为一个l
    $ echo 'hello' | tr -s 'l'
    # 将输入文本,全部转换为大写或小写输出
    $ cat /etc/passwd | tr '[:lower:]' '[:upper:]'
    # 上面的'[:lower:]' '[:upper:]'你也可以简单的写作'[a-z]' '[A-Z]',当然反过来将大写变小写也是可以的

    col命令进行转换

    使用方法
    col [option]

    选项
    选项 说明
    -x 将Tab转换为空格
    -h 将空格转换为Tab(默认选项)

    cat命令打印文件内容

    打印文件内容,加重定向可实现复制功能:

    • cat 01.py > laowang.txt,把文件01.py的内容添加到laowang.txt中。
      同时打印多个文件的内容,后面的文件在后面显示

    • cat 01.py 02.py > laozhang.txt: 合并多个文件到某个文件中;

    实例:

    # 查看 /etc/protocols 中的不可见字符,可以看到很多 ^I ,这其实就是 Tab 转义成可见字符的符号
    $ cat -A /etc/protocols
    # 使用 col -x 将 /etc/protocols 中的 Tab 转换为空格,然后再使用 cat 查看,你发现 ^I 不见了
    $ cat /etc/protocols | col -x | cat -A

    join命令合并文件内容

    将两个文件中包含相同内容的那一行合并在一起。
    使用方式:
    join [option]... file1 file2

    选项
    选项 说明
    -t 指定分隔符,默认为空格
    -i 忽略大小写的差异
    -1 指明第一个文件要用哪个字段来对比,,默认对比第一个字段
    -2 指明第二个文件要用哪个字段来对比,,默认对比第一个字段

    paste命令合并文件

    join 命令类似,它是在不对比数据的情况下,简单地将多个文件合并一起,以Tab隔开。
    使用方法
    paste [option] file...
    常见参数
    -d 指定合并的分隔符,默认为Tab
    -s 不合并到一行,每个文件为一行

    数据流重定向

    还记得在Linux下输入输出也是文件么,数据流重定向的作用就是将原本输出到标准输出的数据重定向到一个文件中.

    对输入输出的描述--三个特殊设备

    • stdin(标准输入,对应于你在终端的输入),0 /dev/stdin 标准输入

    • stdout(标准输出,对应于终端的输出),1 /dev/stdout 标准输出

    • stderr(标准错误输出,对应于终端的输出)2 /dev/stderr 标准错误

    文件描述符:文件描述符在形式上是一个非负整数。实际上,它是一个索引值,指向内核为每一个进程所维护的该进程打开文件的记录表。当程序打开一个现有文件或者创建一个新文件时,内核向进程返回一个文件描述符。在程序设计中,一些涉及底层的程序编写往往会围绕着文件描述符展开。但是文件描述符这一概念往往只适用于 UNIX、Linux 这样的操作系统。

    重定向模式有两种:
    >:将标准输出导向一个文件(如果该文件已经存在,则清空之前的文件)
    >>:将标准输出追加到一个文件中

    使用实例

    ➜  ~ echo 'lalala' > redirect
    ➜  ~ echo 'lalalalala' >> redirect
    ➜  ~ cat redirect                           
    lalala
    lalalalala
    ➜  ~ 

    标准错误输出的重定向

    # 将标准错误重定向到标准输出,再将标准输出重定向到文件,注意要将重定向到文件写到前面
    $ cat Documents/test.c hello.c >somefile  2>&1
    # 或者只用bash提供的特殊的重定向符号"&"将标准错误和标准输出同时重定向到文件
    $ cat Documents/test.c hello.c &>somefilehell

    使用tee命令同时重定向到多个文件

    将需要将输出重定向到文件之外也需要将信息打印在终端

    ➜  ~ echo 'hello shiyanlou' | tee hello                                                   
    hello shiyanlou
    ➜  ~ cat hello
    hello shiyanlou
    ➜  ~ 

    永久重定向exec命令

    可以使用exec命令实现“永久”重定向。exec命令的作用是使用指定的命令替换当前的 Shell,及使用一个进程替换当前进程,或者指定新的重定向:

    # 先开启一个子 Shell
    $ zsh
    # 使用exec替换当前进程的重定向,将标准输出重定向到一个文件
    $ exec 1>somefile
    # 后面你执行的命令的输出都将被重定向到文件中,直到你退出当前子shell,或取消exec的重定向(后面将告诉你怎么做)
    $ ls
    $ exit
    $ cat somefile
    
    Applications
    Calibre 书库
    Desktop
    Documents
    Downloads
    Dropbox
    Git
    GitBook
    Library
    Movies
    Music
    Pictures
    Projects
    Public
    WebstormProjects

    创建输出文件描述符

    默认在 Shell 中可以有9个打开的文件描述符,上面我们使用了也是它默认提供的0,1,2号文件描述符,另外我们还可以使用3-8的文件描述符,只是它们默认没有打开而已

    使用下面命令查看当前 Shell 进程中打开的文件描述符:

    $ cd /dev/fd/;ls -Al

    使用exec命令可以创建新的文件描述符

    $ zsh
    $ exec 3>somefile
    # 先进入目录,再查看,否则你可能不能得到正确的结果,然后再回到上一次的目录
    $ cd /dev/fd/;ls -Al;cd -
    # 注意下面的命令>与&之间不应该有空格,如果有空格则会出错
    $ echo "this is test" >&3
    $ cat somefile
    $ exit
    
    $ exec 3>&-
    $ cd /dev/fd;ls -Al;cd -

    完全屏蔽命令的输出 黑洞

    在类 UNIX 系统中,/dev/null,或称空设备,是一个特殊的设备文件,它通常被用于丢弃不需要的输出流,或作为用于输入流的空文件,这些操作通常由重定向完成。读取它则会立即得到一个EOF。

    $ cat Documents/test.c nefile 1>/dev/null 2>&1

    日志系统

    查看日志可以帮我们了解很多问题

    常见的日志一般存放在 /var/log 中

    日志的分类

    • 系统日志

    • 应用日志

    系统日志主要是存放系统内置程序或系统内核之类的日志信息如 alternatives.log 、btmp 等等,应用日志主要是我们装的第三方应用所产生的日志如 tomcat7 、apache2 等等。

    对不同日志名称及其描述如下:
    日志名称 记录信息

    • alternatives.log 系统的一些更新替代信息记录

    • apport.log 应用程序崩溃信息记录

    • apt/history.log 使用apt-get安装卸载软件的信息记录

    • apt/term.log 使用apt-get时的具体操作,如 package 的下载打开等

    • auth.log 登录认证的信息记录

    • boot.log 系统启动时的程序服务的日志信息

    • btmp 错误登陆的信息记录

    • Consolekit/history 控制台的信息记录

    • dist-upgrade dist-upgrade这种更新方式的信息记录

    • dmesg 启动时,显示屏幕上内核缓冲信息,与硬件有关的信息

    • dpkg.log dpkg命令管理包的日志。

    • faillog 用户登录失败详细信息记录

    • fontconfig.log 与字体配置有关的信息记录

    • kern.log 内核产生的信息记录,在自己修改内核时有很大帮助

    • lastlog 用户的最近信息记录

    • wtmp 登录信息的记录。wtmp可以找出谁正在登陆进入系统,谁使用命令显示这个文件或信息等

    • syslog 系统信息记录

    查看方法
    less auth.log
    当然查看也可以用之前接触到的其它方法morecat等等。

    注:wtmp,lastlog两个日志不能直接用 less、cat、more 这样的工具来查看。其查看方法是使用last 与 lastlog 工具来提取其中的信息

    日志的产生

    • 一种是由软件开发商自己来自定义日志格式然后指定输出日志位置,

      • 还有一种方式就是 Linux 提供的日志服务程序,而我们这里系统日志是通过 syslog 来实现,提供日志管理服务。

    syslog 是一个系统日志记录程序,在早期的大部分 Linux 发行版都是内置 syslog,让其作为系统的默认日志收集工具,虽然时代的进步与发展,syslog 已经年老体衰跟不上时代的需求,所以他被 rsyslog 所代替了,较新的Ubuntu、Fedora 等等都是默认使用 rsyslog 作为系统的日志收集工具

    # 开启
    sudo service rsyslog start
    
    ps aux | grep syslog

    rsyslog 的配置文件有两个,

    • 一个是 /etc/rsyslog.conf :第一个主要是配置的环境,也就是 rsyslog 的加载什么模块,文件的所属者等;

    • 一个是 /etc/rsyslog.d/50-default.conf。而第二个主要是配置的 Filter Conditions;

    rsyslog 主要是由 Input、Output、Parser 这样三个模块构成的,并且了解到数据的简单走向,首先通过 Input module 来收集消息,然后将得到的消息传给 Parser module,通过分析模块的层层处理,将真正需要的消息传给 Output module,然后便输出至日志文件中。

    参考资料

    又是好长的一篇读书笔记,希望你在看完之后有所收获,希望本文能助你打开Linux的使用大门,附上我觉得比较好shell,Linux学习资料如下:

    多练习总能有所收获,祝学习愉快?。


    zhangwang
    8k 声望1.8k 粉丝

    前端,摄影,阅读,好奇