linux基础_linux常用命令大全(linux基础命令入门 - CSDN
  • Linux基础知识

    2020-06-11 17:14:52
    1.计算机硬件的五大部分: 输入单元、输出单元、主存储器、CPU内部的控制单元、算数逻辑单元 1.1传输数据过程: 输入单元–主存储器–CPU–主存储器–输出单元 2.世界主流的两种CPU架构 精简指令集系统(RISC):ARM...

    1.计算机硬件的五大部分:

    输入单元、输出单元、主存储器、CPU内部的控制单元、算数逻辑单元
    1.1传输数据过程:
    输入单元–主存储器–CPU–主存储器–输出单元

    2.世界主流的两种CPU架构

    精简指令集系统(RISC):ARM CPU系列(世界上使用范围最广的CPU)
    复杂指令集系统(CISC):AMD、Intel、VIA 等的x86 架构的CPU
    注:所谓的位指的是CPU 一次数据读取的最大量!64 位CPU 代表CPU 一次可以读写64bits这么多的数

    3.容量单位

    0/1 这个二进制的的单位我们称为bit,1byte=8bits,K 代表1024 byte,M 代表1024K,常见的单位与进位制的关系:
    在这里插入图片描述

    4.操作系统

    在这里插入图片描述

    核心功能

    1.系统呼叫接口(System call interface)
    2.程序管理(Process control)
    3.内存管理(Memory management)
    4.文件系统管理(Filesystem management)
    5.装置的驱动(Device drivers)

    展开全文
  • linux使用入门教程

    2020-07-13 15:53:31
    说实话在第一次接触Linux系统时,确实很不习惯,尤其是在用了多年的Windows后,可是项目需要又不得不顶着头皮去学习了,下面就自己一点点摸索做下总结,以供后面学习。 1、安装Linux系统 由于Linux的开源性,我们...

    说实话在第一次接触Linux系统时,确实很不习惯,尤其是在用了多年的Windows后,可是项目需要又不得不顶着头皮去学习了,下面就自己一点点摸索做下总结,以供后面学习。

    1、安装Linux系统

    由于Linux的开源性,我们可以有很多选择,常见的有Ubuntu,centos,Fedora, Debian ,RedhatEnterpriseLinux ,SUSE OpenSUSE,Mindriva, Gentoo, Arch , Slackware等等这些主流发行版几乎占据了大多份额。这里我选择的是Ubuntu16.04,至于安装可以参照我的另一篇博客《Windows+Ubuntu双系统安装》

    2、预装软件

    当你成功安装了Linux系统后,你会发现桌面像这样

    系统给你预装了一些软件,但是这不一定你用的习惯,首当其冲就是输入法啦!没有习惯的搜狗输入法,我们还怎么愉快的玩耍,故此第一个安装的软件肯定就是输入法了。针对次,搜狗推出了针对Linux版本,下载链接:https://pinyin.sogou.com/linux/

    安装教程可以参考https://blog.csdn.net/u013894834/article/details/60357071或https://blog.csdn.net/iamplane/article/details/70447517。

    还有我们经常办公用的QQ怎么办,毕竟我们习惯了打开电脑登上QQ的生活,可是小马哥没有针对Linux系统开发对应版本的QQ,这可如何是好。这时候广大的人民群众站起来了,我们自己解决问题,大牛们开发出来了Wine-QQ与Wine-TIM的Appimage版本,下载安装链接https://github.com/Albert337/Wine-QQ-TIM,下载后你会发现是这样的

                                                                    

     

    不是我们常见的后缀exe格式哦,而是APPiMage格式,想要运行它,我们先要修改一下他的权限,选中右键点击属性,在权限那一页,勾选允许作为程序执行文件,效果如下图:

    然后我们双击它后我们就可以见到我们经典的登录界面啦。

     

    3、使用技巧

    在Linux下我们最常见的就是在终端进行一些操作,打开终端的方式有很多种,鼠标右键选择打开终端,或者快捷键Ctrl+Alt+T,接下来我们介绍一下Linux常用的命令:

    (1)查看目录:ls用于查看当前路径下所有文件信息

     

    补:

    查看linux文件的权限:ls -l 文件名称(可以简单输入ll也行)

    查看linux文件夹的权限:ls -ld 文件夹名称(所在目录)

    (2)创建目录:mkdir 创建文件夹

    (3)切换目录:cd 切换到指定文件

     

    (4)复制文件、目录:cp(源文件)(目标件)

    cp-r 可以指定拷贝指定的任意目录(包括子目录和文件)

    cp- f 删除已经存在的目标文件而不提示。

    cp- i 和f选项相反,在覆盖目标文件之前将给出提示要求用户确认。回答y时目标文件将被覆盖,是交互式拷贝。

    (4)删除文件、目录:rm (文件或目录)

    rm-rf可以指定删除任意的目录或文件,慎用。

    rm dir删除空文件夹

     

    (5)重命名或剪切文件:mv(文件或目录名/旧地址)(新名字/新地址)

     

    (6)简单的编辑器nano

    nano temp.py 会生成一个脚本,进入编辑框

    在编辑完后按住Ctrl+x离开保存即可。

    (7)读取命令cat

    cat有两种用法,一是将文件内容全部显示在屏幕上 cat temp.py

    二是将一个文件内容放到另一个文件内,相当于cp命令 cattemp.py temp1.py

    ****对于文件的读取操作等,还可以借助vim编辑器或gedit编辑器,这可以参考我的另一篇博客https://blog.csdn.net/xiaomu_347/article/details/97818052

    4、常见文件的打开方式

    • deb包-是Ubuntu的专利,在Ubuntu中双击deb包就可以进入自动安装进程  dpkg -i xxx.deb即可
    • rpm包-在红帽LINUX、SUSE、Fedora可以直接进行安装,但在Ubuntu中却无法识别
    • whl包:已经编译的包,类似于exe文件,先安装wheel包后,再利用pip install xx.whl来安装即可。
    • tar包:源文件,只是打包在一起,还没有编译,在所有的Linux版本中都能使用,用归档管理器提取。

                      同样针对.tar包可以利用 tar –xvf 解压   压缩:tar –cvf jpg.tar *.jpg //将目录里所有jpg文件打包成tar.jpg

    • tar.gz包:源文件,压缩并打包在一起,还没有编译,在所有的Linux版本中都能使用,用归档管理器提取。

                       同样针对.tar.gz包可以利用 tar –zxvf 解压  压缩:tar –czf jpg.tar.gz *.jpg  //生成一个gzip压缩过的包,命名为 .

                       jpg.tar.gz

    tar命令
    
      解包:tar -zxvf FileName.tar
    
      打包:tar -czvf FileName.tar DirName
    
    gz命令
    
      解压1:gunzip FileName.gz
    
      解压2:gzip -d FileName.gz
    
      压缩:gzip FileName
    
      .tar.gz 和 .tgz
    
      解压:tar -zxvf FileName.tar.gz
    
      压缩:tar -zcvf FileName.tar.gz DirName
    
       压缩多个文件:tar zcvf FileName.tar.gz DirName1 DirName2 DirName3 ...
    
    bz2命令
    
      解压1:bzip2 -d FileName.bz2
    
      解压2:bunzip2 FileName.bz2
    
      压缩: bzip2 -z FileName
    
      .tar.bz2
    
      解压:tar jxvf FileName.tar.bz2
    
      压缩:tar jcvf FileName.tar.bz2 DirName
    
    bz命令
    
      解压1:bzip2 -d FileName.bz
    
      解压2:bunzip2 FileName.bz
    
      压缩:未知
    
      .tar.bz
    
      解压:tar jxvf FileName.tar.bz
    
    Z命令
    
      解压:uncompress FileName.Z
    
      压缩:compress FileName
    
      .tar.Z
    
      解压:tar Zxvf FileName.tar.Z
    
      压缩:tar Zcvf FileName.tar.Z DirName
    
    zip命令
    
      解压:unzip FileName.zip
    
      压缩:zip FileName.zip DirName
    
    

    注:

    • 关于Linux下的权限不够问题,我们在命令前面加上sudo即可。

    • 针对切换命令cd,有一些默认小命令 cd/ 表示进入根目录 ;cd或cd~进入用户home目录;cd-表示进入上一次访问的目录,相当于back;cd .. 进入上级目录

    • pwd结果显示当前目录或者ctrl+l可以快速查看路径

    • ifconfig显示系统的网络IP信息

    • man显示某个命令的manual(指南)

    • dpkg -l可以查看电脑上安装的软件信息

    • 对函数或包不熟悉时,用help(函数、包)查看详细信息

    • xdg-open加上路径会以默认方式打开文件

    • sudo chmod -(代表类型)×××(所有者)×××(组用户)×××(其他用户)可以修改文件及文件夹属性。

    • 新建用户的命令不同第一种是useradd, 第二种是adduser。相对应的,如果要删除用户,第一种的命令为userdel, 第二种是deluser,推荐使用第二种,这样会自动赋予sudo权限。同时进行用户切换命令可用:切换到root(sudo su 或su - root)

    更多的Linux指令参考以下链接:https://www.cnblogs.com/evolve/p/9129339.html

     

    展开全文
  • Linux入门教程

    2018-03-11 21:05:28
    Linux 入门教程 Linux简介 严格的来讲,Linux 不算是一个操作系统,只是一个 Linux 系统中的内核,即计算机软件与硬件通讯之间的平台;Linux的全称是GNU/Linux,这才算是一个真正意义上的Linux系统。GNU是Richard ...

    Linux 入门教程

    Linux简介

    严格的来讲,Linux 不算是一个操作系统,只是一个 Linux 系统中的内核,即计算机软件与硬件通讯之间的平台;Linux的全称是GNU/Linux,这才算是一个真正意义上的Linux系统。GNU是Richard Stallman组织的一个项目,世界各地的程序员可以变形GNU程序,同时遵循GPL协议,允许任何人任意改动。但是,修改后的程序必须遵循GPL协议。

    Linux 是一个多用户多任务的操作系统,也是一款自由软件,完全兼容POSIX标准,拥有良好的用户界面,支持多种处理器架构,移植方便。

    为程序分配系统资源,处理计算机内部细节的软件叫做操作系统或者内核。如果你希望详细了解操作系统的概念,请查看操作系统教程

    用户通过Shell与Linux内核交互。Shell是一个命令行解释工具(是一个软件),它将用户输入的命令转换为内核能够理解的语言(命令)。

    Linux下,很多工作都是通过命令完成的,学好Linux,首先要掌握常用命令。

    Linux版本

    内核版本指的是在 Linus 领导下的开发小组开发出的系统内核的版本号。Linux 的每个内核版本使用形式为 x.y.zz-www 的一组数字来表示。其中:

    • x.y:为linux的主版本号。通常y若为奇数,表示此版本为测试版,系统会有较多bug,主要用途是提供给用户测试。
    • zz:为次版本号。
    • www:代表发行号(注意,它与发行版本号无关)。


      当内核功能有一个飞跃时,主版本号升级,如 Kernel2.2、2.4、2.6等。如果内核增加了少量补丁时,常常会升级次版本号,如Kernel2.6.15、2.6.20等。

      一些组织或厂家将 Linux 内核与GNU软件(系统软件和工具)整合起来,并提供一些安装界面和系统设定与管理工具,这样就构成了一个发型套件,例如Ubuntu、Red Hat、Centos、Fedora、SUSE、Debian、FreeBSD等。相对于内核版本,发行套件的版本号随着发布者的不同而不同,与系统内核的版本号是相对独立的。因此把Red Hat等直接说成是Linux是不确切的,它们是Linux的发行版本,更确切地说,应该叫做"以linux为核心的操作系统软件包"。

      Linux体系结构

      下面是Linux体系结构的示意图:


      在所有Linux版本中,都会涉及到以下几个重要概念:

    • 内核:内核是操作系统的核心。内核直接与硬件交互,并处理大部分较低层的任务,如内存管理、进程调度、文件管理等。
    • Shell:Shell是一个处理用户请求的工具,它负责解释用户输入的命令,调用用户希望使用的程序。
    • 命令和工具:日常工作中,你会用到很多系统命令和工具,如cp、mv、cat和grep等。在Linux系统中,有250多个命令,每个命令都有多个选项;第三方工具也有很多,他们也扮演着重要角色。
    • 文件和目录:Linux系统中所有的数据都被存储到文件中,这些文件被分配到各个目录,构成文件系统。Linux的目录与Windows的文件夹是类似的概念。

      系统启动(开机)

      如果你有一台装有Linux的电脑,加电后系统会自动启动,然后提示你登录系统,只有登录后才能进行其他操作。

      登录Linux

      第一次使用Linux,会看到登录的提示,如下所示:

      login:
      

      登录步骤:

    • 登录Linux必须有用户名(用户ID)和密码,如果没有,可以向管理员所要。
    • 在登录提示处输入用户名并回车;用户名是区分大小写的,输入时要注意。
    • 然后会提示你输入密码,密码也是区分大小写的。
    • 如果用户名和密码正确,那么会成功登录,并看到上次登录信息。

      login : amrood
      amrood's password:
      Last login: Sun Jun 14 09:32:32 2009 from 62.61.164.73
      $
      

      登录后会出现命令提示符($),你可以输入任何命令。下面通过 cal 命令来查看日历:

      $ cal
           June 2009
      Su Mo Tu We Th Fr Sa
          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
      
      $
      

      修改密码

      Linux系统通过密码来保证数据和文件的安全,防止黑客破解和攻击。你可以通过以下方法来修改密码:

    • 输入 password 命令。
    • 输入你现在使用的密码。
    • 输入新密码。注意密码不要过于简单,简单的密码往往会为入侵者大开便利之门。
    • 确认密码,再输入一遍刚才的密码。

      $ passwd
      Changing password for amrood
      (current) Linux password:******
      New Linux password:*******
      Retype new Linux password:*******
      passwd: all authentication tokens updated  successfully
      
      $
      

      注意:输入的密码是看不到的,只会看到一个占位符(*)。

      查看目录和文件

      在Linux中,所有的数据都被保存在文件中,所有的文件又被分配到不同的目录;目录是一种类似树的结构,称为文件系统。

      你可以使用 ls 命令来查看当前目录下的文件和目录。下面的例子,使用了 ls 命令的 -l 选项:

      $ ls -l
      total 19621
      drwxrwxr-x  2 amrood amrood      4096 Dec 25 09:59 uml
      -rw-rw-r--  1 amrood amrood      5341 Dec 25 08:38 uml.jpg
      drwxr-xr-x  2 amrood amrood      4096 Feb 15  2006 univ
      drwxr-xr-x  2 root   root        4096 Dec  9  2007 urlspedia
      -rw-r--r--  1 root   root      276480 Dec  9  2007 urlspedia.tar
      drwxr-xr-x  8 root   root        4096 Nov 25  2007 usr
      -rwxr-xr-x  1 root   root        3192 Nov 25  2007 webthumb.php
      -rw-rw-r--  1 amrood amrood     20480 Nov 25  2007 webthumb.tar
      -rw-rw-r--  1 amrood amrood      5654 Aug  9  2007 yourfile.mid
      -rw-rw-r--  1 amrood amrood    166255 Aug  9  2007 yourfile.swf
      
      $
      

      注意:以 d* 开头的为目录,如 uml、univ、urlspedia等;其他的都是文件。

      查看当前用户信息

      登录系统后,如果你希望知道自己的用户名(用户ID),可以使用 whoami 命令:

      $ whoami
      amrood
      
      $
      

      如果你希望了解更多关于当前用户的信息,可以使用 who am i 命令,读者可以自己尝试一下。

      查看当前在线用户

      如果你希望知道当前在线的用户(同时登录到系统的用户),可以使用 users、who 和 w 命令:

      $ users
      amrood bablu qadir
      
      $ who
      amrood ttyp0 Oct 8 14:10 (limbo)
      bablu  ttyp2 Oct 4 09:08 (calliope)
      qadir  ttyp4 Oct 8 12:09 (dent)
      
      $
      

      w 命令可以看到在线用户的更多信息,读者可以自己尝试。

      退出登录

      完成工作后,你需要退出系统,防止他人使用你的账户。

      使用 logout 命令即可退出登录,系统会清理有关信息并断开连接。

      关闭系统(关机)

      关系Linux系统可以使用下列命令:

      命令

      说明

      halt

      直接关闭系统

      init 0

      使用预先定义的脚本关闭系统,关闭前可以清理和更新有关信息

      init 6

      重新启动系统

      poweroff

      通过断电来关闭系统

      reboot

      重新启动系统

      shutdown

      安全关闭系统

      注意:一般情况下只有超级用户和root用户(Linux系统中的最高特权用户)才有关闭系统的权限,但是给普通用户赋予相应权限也可以关闭系统。

       

       

      Linux文件管理

       

      Linux中的所有数据都被保存在文件中,所有的文件被分配到不同的目录。目录是一种类似于树的结构,称为文件系统。

      当你使用Linux时,大部分时间都会和文件打交道,通过本节可以了解基本的文件操作,如创建文件、删除文件、复制文件、重命名文件以及为文件创建链接等。

      在Linux中,有三种基本的文件类型:

      1) 普通文件

      普通文件是以字节为单位的数据流,包括文本文件、源码文件、可执行文件等。文本和二进制对Linux来说并无区别,对普通文件的解释由处理该文件的应用程序进行。

      2) 目录

      目录可以包含普通文件和特殊文件,目录相当于Windows和Mac OS中的文件夹。

      3) 设备文件

      有些教程中称特殊文件,是一个含义。Linux 与外部设备(例如光驱,打印机,终端,modern等)是通过一种被称为设备文件的文件来进行通信。Linux 输入输出到外部设备的方式和输入输出到一个文件的方式是相同的。Linux 和一个外部设备通讯之前,这个设备必须首先要有一个设备文件存在。

      例如,每一个终端都有自己的设备文件来供 Linux 写数据(出现在终端屏幕上)和读取数据(用户通过键盘输入)。

      设备文件和普通文件不一样,设备文件中并不包含任何数据。

      设备文件有两种类型:字符设备文件和块设备文件。

    • 字符设备文件以字母"c"开头。字符设备文件向设备传送数据时,一次传送一个字符。典型的通过字符传送数据的设备有终端、打印机、绘图仪、modern等。字符设备文件有时也被称为"raw"设备文件。
    • 块设备文件以字母"b"开头。块设备文件向设备传送数据时,先从内存中的buffer中读或写数据,而不是直接传送数据到物理磁盘。磁盘和CD-ROMS既可以使用字符设备文件也可以使用块设备文件。

      查看文件

      查看当前目录下的文件和目录可以使用 ls 命令,例如:

      $ls
      
      bin        hosts  lib     res.03
      ch07       hw1    pub     test_results
      ch07.bak   hw2    res.01  users
      docs       hw3    res.02  work
      

      通过 ls 命令的 -l 选项,你可以获取更多文件信息,例如:

      $ls -l
      total 1962188
      
      drwxrwxr-x  2 amrood amrood      4096 Dec 25 09:59 uml
      -rw-rw-r--  1 amrood amrood      5341 Dec 25 08:38 uml.jpg
      drwxr-xr-x  2 amrood amrood      4096 Feb 15  2006 univ
      drwxr-xr-x  2 root   root        4096 Dec  9  2007 urlspedia
      -rw-r--r--  1 root   root      276480 Dec  9  2007 urlspedia.tar
      drwxr-xr-x  8 root   root        4096 Nov 25  2007 usr
      drwxr-xr-x  2    200    300      4096 Nov 25  2007 webthumb-1.01
      -rwxr-xr-x  1 root   root        3192 Nov 25  2007 webthumb.php
      -rw-rw-r--  1 amrood amrood     20480 Nov 25  2007 webthumb.tar
      -rw-rw-r--  1 amrood amrood      5654 Aug  9  2007 yourfile.mid
      -rw-rw-r--  1 amrood amrood    166255 Aug  9  2007 yourfile.swf
      drwxr-xr-x 11 amrood amrood      4096 May 29  2007 zlib-1.2.3
      $
      

      每一列的含义如下:

    • 第一列:文件类型。
    • 第二列:表示文件个数。如果是文件,那么就是1;如果是目录,那么就是该目录中文件的数目。
    • 第三列:文件的所有者,即文件的创建者。
    • 第四列:文件所有者所在的用户组。在Linux中,每个用户都隶属于一个用户组。
    • 第五列:文件大小(以字节计)。
    • 第六列:文件被创建或上次被修改的时间。
    • 第七列:文件名或目录名。


      注意:每一个目录都有一个指向它本身的子目录"." 和指向它上级目录的子目录"..",所以对于一个空目录,第二列应该为 2。

      通过 ls -l 列出的文件,每一行都是以 a、d、- 或 l 开头,这些字符表示文件类型:

      前缀

      描述

      -

      普通文件。如文本文件、二进制可执行文件、源代码等。

      b

      块设备文件。硬盘可以使用块设备文件。

      c

      字符设备文件。硬盘也可以使用字符设备文件。

      d

      目录文件。目录可以包含文件和其他目录。

      l

      符号链接(软链接)。可以链接任何普通文件,类似于 Windows 中的快捷方式。

      p

      具名管道。管道是进程间的一种通信机制。

      s

      用于进程间通信的套接字。


      提示:通俗的讲软连接就是windows的快捷方式,原来文件删了,快捷方式虽然在但是不起作用了。

      元字符

      元字符是具有特殊含义的字符。* 和 ? 都是元字符:

    • * 可以匹配 0 个或多个任意字符;
    • ? 匹配一个字符。


      例如

      $ls ch*.doc
      

      可以显示所有以 ch 开头,以 .doc 结尾的文件:

      ch01-1.doc   ch010.doc  ch02.doc    ch03-2.doc
      ch04-1.doc   ch040.doc  ch05.doc    ch06-2.doc
      ch01-2.doc ch02-1.doc c
      

      这里,* 匹配任意一个字符。如果你希望显示所有以 .doc 结尾的文件,可以使用

      $ls *.doc。
      

      隐藏文件

      隐藏文件的第一个字符为英文句号或点号(.),Linux程序(包括Shell)通常使用隐藏文件来保存配置信息。

      下面是一些常见的隐藏文件:
      .profile:Bourne shell (sh) 初始化脚本
      .kshrc:Korn shell (ksh) 初始化脚本
      .cshrc:C shell (csh) 初始化脚本
      .rhosts:Remote shell (rsh) 配置文件

      查看隐藏文件需要使用 ls 命令的 -a 选项:

      $ ls -a
      
      .         .profile       docs     lib     test_results
      ..        .rhosts        hosts    pub     users
      .emacs    bin            hw1      res.01  work
      .exrc     ch07           hw2      res.02
      .kshrc    ch07.bak       hw3      res.03
      $
      

      一个点号(.)表示当前目录,两个点号(..)表示上级目录

      注意:输入密码时,星号(*)作为占位符,代表你输入的字符个数。

      创建文件

      在Linux中,可以使用 vi 编辑器创建一个文本文件,例如:

      $ vi filename
      

      上面的命令会创建文件 filename 并打开,按下 i 键即可进入编辑模式,你可以向文件中写入内容。例如:

      This is Linux file....I created it for the first time.....
      I'm going to save this content in this file.
      

      完成编辑后,可以按 esc 键退出编辑模式,也可以按组合键 Shift + ZZ 完全退出文件。这样,就完成了文件的创建。

      $ vi filename
      $
      

      编辑文件

      vi 编辑器可以用来编辑文件。由于篇幅限制,这里仅作简单介绍,将在后面章节进行详细讲解。

      如下可以打开一个名为 filename 的文件:

      $ vi filename
      

      当文件被打开后,可以按 i 键进入编辑模式,按照自己的方式编辑文件。如果想移动光标,必须先按 esc 键退出编辑模式,然后使用下面的按键在文件内移动光标:

    • l 键向右移动
    • h 键向左移动
    • k 键向上移动
    • j 键向下移动


      使用上面的按键,可以将光标快速定位到你想编辑的地方。定位好光标后,按 i 键再次进入编辑模式。编辑完成后按 esc 键退出编辑模式或者按组合键 Shift+ZZ 退出当前文件。

      查看文件内容

      可以使用 cat 命令来查看文件内容,下面是一个简单的例子:

      $ cat filename
      This is Linux file....I created it for the first time.....
      I'm going to save this content in this file.
      $
      

      可以通过 cat 命令的 -b 选项来显示行号,例如:

      $ cat -b filename
      1   This is Linux file....I created it for the first time.....
      2   I'm going to save this content in this file.
      $
      

      统计单词数目

      可以使用 wc 命令来统计当前文件的行数、单词数和字符数,下面是一个简单的例子:

      $ wc filename
      2  19 103 filename
      $
      

      每一列的含义如下:

    • 第一列:文件的总行数
    • 第二列:单词数目
    • 第三列:文件的字节数,即文件的大小
    • 第四列:文件名


      也可以一次查看多个文件的内容,例如:

      $ wc filename1 filename2 filename3
      

      复制文件

      可以使用 cp 命令来复制文件。cp 命令的基本语法如下:

      $ cp source_file destination_file
      

      下面的例子将会复制 filename 文件:

      $ cp filename copyfile
      $
      

      现在在当前目录中会多出一个和 filename 一模一样的 copyfile 文件。

      重命名文件

      重命名文件可以使用 mv 命令,语法为:

      $ mv old_file new_file
      

      下面的例子将会把 filename 文件重命名为 newfile:

      $ mv filename newfile
      $
      

      现在在当前目录下,只有一个 newfile 文件。

      mv 命令其实是一个移动文件的命令,不但可以更改文件的路径,也可以更改文件名。

      删除文件

      rm命令可以删除文件,语法为:

      $ rm filename
      

      注意:删除文件是一种危险的行为,因为文件内可能包含有用信息,建议结合 -i 选项来使用 rm 命令。

      下面的例子会彻底删除一个文件:

      $ rm filename
      $
      

      你也可以一次删除多个文件:

      $ rm filename1 filename2 filename3
      $
      

      标准的Linux流

      一般情况下,每个Linux程序运行时都会创建三个文件流(三个文件):

    • 标准输入流(stdin):stdin的文件描述符为0,Linux程序默认从stdin读取数据。
    • 标准输出流(stdout):stdout 的文件描述符为1,Linux程序默认向stdout输出数据。
    • 标准错误流(stderr):stderr的文件描述符为2,Linux程序会向stderr流中写入错误信息。

      Linux目录

      目录也是一个文件,它的唯一功能是用来保存文件及其相关信息。所有的文件,包括普通文件、设备文件和目录文件,都会被保存到目录中。

      主目录

      登录后,你所在的位置就是你的主目录(或登录目录),接下来你主要是在这个目录下进行操作,如创建文件、删除文件等。

      使用下面的命令可以随时进入主目录:

      $cd ~
      $
      

      这里 ~ 就表示主目录。如果你希望进入其他用户的主目录,可以使用下面的命令:

      $cd ~username
      $
      

      返回进入当前目录前所在的目录可以使用下面的命令:

      $cd -
      $
      

      绝对路径和相对路径

      Linux 的目录有清晰的层次结构,/ 代表根目录,所有的目录都位于 / 下面;文件在层次结构中的位置可以用路径来表示。

      如果一个路径以 / 开头,就称为绝对路径;它表示当前文件与根目录的关系。举例如下:

      /etc/passwd
      /users/sjones/chem/notes
      /dev/rdsk/Os3
      

      不以 / 开头的路径称为相对路径,它表示文件与当前目录的关系。例如:

      chem/notes
      personal/res
      

      获取当前所在的目录可以使用 pwd 命令:

      $pwd
      /user0/home/amrood
      
      $
      

      查看目录中的文件可以使用 ls 命令:

      $ls dirname
      

      下面的例子将遍历 /usr/local 目录下的文件:

      $ls /usr/local
      
      X11       bin          gimp       jikes       sbin
      ace       doc          include    lib         share
      atalk     etc          info       man         ami
      

      创建目录

      可以使用 mkdir 命令来创建目录,语法为:

      $mkdir dirname
      

      dirname 可以为绝对路径,也可以为相对路径。例如

      $mkdir mydir
      $
      

      会在当前目录下创建 mydir 目录。又如

      $mkdir /tmp/test-dir
      $
      

      会在 /tmp 目录下创建 test-dir 目录。mkdir 成功创建目录后不会输出任何信息。

      也可以使用 mkdir 命令同时创建多个目录,例如

      $mkdir docs pub
      $
      

      会在当前目录下创建 docs 和 pub 两个目录。

      创建父目录

      使用 mkdir 命令创建目录时,如果上级目录不存在,就会报错。下面的例子中,mkdir 会输出错误信息:

      $mkdir /tmp/amrood/test
      mkdir: Failed to make directory "/tmp/amrood/test";
      No such file or directory
      $
      

      为 mkdir 命令增加 -p 选项,可以一级一级创建所需要的目录,即使上级目录不存在也不会报错。例如

      $mkdir -p /tmp/amrood/test
      $
      

      会创建所有不存在的上级目录。

      删除目录

      可以使用 rmdir 命令来删除目录,例如:

      $rmdir dirname
      $
      

      注意:删除目录时请确保目录为空,不会包含其他文件或目录。

      也可以使用 rmdir 命令同时删除多个目录:

      $rmdir dirname1 dirname2 dirname3
      $
      

      如果 dirname1、dirname2、dirname3 为空,就会被删除。rmdir 成功删除目录后不会输出任何信息。

      改变所在目录

      可以使用 cd 命令来改变当前所在目录,进入任何有权限的目录,语法为:

      $cd dirname
      

      dirname 为路径,可以为相对路径,也可以为绝对路径。例如

      $cd /usr/local/bin
      $
      

      可以进入 /usr/local/bin 目录。可以使用相对路径从这个目录进入 /usr/home/amrood 目录:

      $cd ../../home/amrood
      $
      

      重命名目录

      mv (move) 命令也可以用来重命名目录,语法为:

      $mv olddir newdir
      

      下面的例子将会把 mydir 目录重命名为 yourdir 目录:

      $mv mydir yourdir
      $
      

      点号(.)

      一个点号(.)表示当前目录,两个点号(..)表示上级目录(父目录)。

      ls 命令的 -a 选项可以查看所有文件,包括隐藏文件;-l 选项可以查看文件的所有信息,共有7列。例如:

      $ls -la
      drwxrwxr-x    4    teacher   class   2048  Jul 16 17.56 .
      drwxr-xr-x    60   root              1536  Jul 13 14:18 ..
      ----------    1    teacher   class   4210  May 1 08:27 .profile
      -rwxr-xr-x    1    teacher   class   1948  May 12 13:42 memo
      $
      

      Linux文件权限和访问模式

      为了更加安全的存储文件,Linux为不同的文件赋予了不同的权限,每个文件都拥有下面三种权限:

    • 所有者权限:文件所有者能够进行的操作
    • 组权限:文件所属用户组能够进行的操作
    • 外部权限(其他权限):其他用户可以进行的操作。

      查看文件权限

      使用 ls -l 命令可以查看与文件权限相关的信息:

      $ls -l /home/amrood
      -rwxr-xr--  1 amrood   users 1024  Nov 2 00:10  myfile
      drwxr-xr--- 1 amrood   users 1024  Nov 2 00:10  mydir
      

      第一列就包含了文件或目录的权限。

      第一列的字符可以分为三组,每一组有三个,每个字符都代表不同的权限,分别为读取(r)、写入(w)和执行(x):

    • 第一组字符(2-4)表示文件所有者的权限,-rwxr-xr-- 表示所有者拥有读取(r)、写入(w)和执行(x)的权限。
    • 第二组字符(5-7)表示文件所属用户组的权限,-rwxr-xr-- 表示该组拥有读取(r)和执行(x)的权限,但没有写入权限。
    • 第三组字符(8-10)表示所有其他用户的权限,rwxr-xr-- 表示其他用户只能读取(r)文件。

      文件访问模式

      文件权限是Linux系统的第一道安全防线,基本的权限有读取(r)、写入(w)和执行(x):

    • 读取:用户能够读取文件信息,查看文件内容。
    • 写入:用户可以编辑文件,可以向文件写入内容,也可以删除文件内容。
    • 执行:用户可以将文件作为程序来运行。

      目录访问模式

      目录的访问模式和文件类似,但是稍有不同:

    • 读取:用户可以查看目录中的文件
    • 写入:用户可以在当前目录中删除文件或创建文件
    • 执行:执行权限赋予用户遍历目录的权利,例如执行 cd 和 ls 命令。

      改变权限

      可以使用 chmod (change mode) 命令来改变文件或目录的访问权限,权限可以使用符号或数字来表示。

      使用符号表示权限

      对于初学者来说最简单的就是使用符号来改变文件或目录的权限,你可以增加(+)和删除(-)权限,也可以指定特定权限。

      符号

      说明

      +

      为文件或目录增加权限

      -

      删除文件或目录的权限

      =

      设置指定的权限


      下面的例子将会修改 testfile 文件的权限:

      $ls -l testfile
      -rwxrwxr--  1 amrood   users 1024  Nov 2 00:10  testfile
      $chmod o+wx testfile
      $ls -l testfile
      -rwxrwxrwx  1 amrood   users 1024  Nov 2 00:10  testfile
      $chmod u-x testfile
      $ls -l testfile
      -rw-rwxrwx  1 amrood   users 1024  Nov 2 00:10  testfile
      $chmod g=rx testfile
      $ls -l testfile
      -rw-r-xrwx  1 amrood   users 1024  Nov 2 00:10  testfile
      

      也可以同时使用多个符号:

      $chmod o+wx,u-x,g=rx testfile
      $ls -l testfile
      -rw-r-xrwx  1 amrood   users 1024  Nov 2 00:10  testfile
      

      使用数字表示权限

      除了符号,也可以使用八进制数字来指定具体权限,如下表所示:

      数字

      说明

      权限

      0

      没有任何权限

      ---

      1

      执行权限

      --x

      2

      写入权限

      -w-

      3

      执行权限和写入权限:1 (执行) + 2 (写入) = 3

      -wx

      4

      读取权限

      r--

      5

      读取和执行权限:4 (读取) + 1 (执行) = 5

      r-x

      6

      读取和写入权限:4 (读取) + 2 (写入) = 6

      rw-

      7

      所有权限: 4 (读取) + 2 (写入) + 1 (执行) = 7

      rwx


      下面的例子,首先使用 ls -1 命令查看 testfile 文件的权限,然后使用 chmod 命令更改权限:

      $ls -l testfile
      -rwxrwxr--  1 amrood   users 1024  Nov 2 00:10  testfile
      $ chmod 755 testfile
      $ls -l testfile
      -rwxr-xr-x  1 amrood   users 1024  Nov 2 00:10  testfile
      $chmod 743 testfile
      $ls -l testfile
      -rwxr---wx  1 amrood   users 1024  Nov 2 00:10  testfile
      $chmod 043 testfile
      $ls -l testfile
      ----r---wx  1 amrood   users 1024  Nov 2 00:10  testfile
      

      更改所有者和用户组

      在Linux中,每添加一个新用户,就会为它分配一个用户ID和群组ID,上面提到的文件权限也是基于用户和群组来分配的。

      有两个命令可以改变文件的所有者或群组:

    • chown:chown 命令是"change owner"的缩写,用来改变文件的所有者。
    • chgrp:chgrp 命令是"change group"的缩写,用来改变文件所在的群组。


      chown 命令用来更改文件所有者,其语法如下:

      $ chown user filelist
      

      user 可以是用户名或用户ID,例如

      $ chown amrood testfile
      $
      

      将 testfile 文件的所有者改为 amrood。

      注意:超级用户 root 可以不受限制的更改文件的所有者和用户组,但是普通用户只能更改所有者是自己的文件或目录。

      chgrp 命令用来改变文件所属群组,其语法为:

      $ chgrp group filelist
      

      group可以是群组名或群组ID,例如

      $ chgrp special testfile
      $
      

      将文件 testfile 的群组改为 special。

      SUID和SGID位

      在Linux中,一些程序需要特殊权限才能完成用户指定的操作。

      例如,用户的密码保存在 /etc/shadow 文件中,出于安全考虑,一般用户没有读取和写入的权限。但是当我们使用passwd 命令来更改密码时,需要对 /etc/shadow 文件有写入权限。这就意味着,passwd 程序必须要给我们一些特殊权限,才可以向 /etc/shadow 文件写入内容。

      Linux 通过给程序设置SUID(Set User ID)和SGID(Set Group ID)位来赋予普通用户特殊权限。当我们运行一个带有SUID位的程序时,就会继承该程序所有者的权限;如果程序不带SUID位,则会根据程序使用者的权限来运行。

      SGID也是一样。一般情况下程序会根据你的组权限来运行,但是给程序设置SGID后,就会根据程序所在组的组权限运行。

      如果程序设置了SUID位,就会在表示文件所有者可执行权限的位置上出现's'字母;同样,如果设置了SGID,就会在表示文件群组可执行权限的位置上出现's'字母。如下所示:

      $ ls -l /usr/bin/passwd
      -r-sr-xr-x  1   root   bin  19031 Feb 7 13:47  /usr/bin/passwd*
      $
      

      上面第一列第四个字符不是'x'或'-',而是's',说明 /usr/bin/passwd 文件设置了SUID位,这时普通用户会以root用户的权限来执行passwd程序。

      注意:小写字母's'说明文件所有者有执行权限(x),大写字母'S'说明程序所有者没有执行权限(x)。

      如果在表示群组权限的位置上出现SGID位,那么也仅有三类用户可以删除该目录下的文件:目录所有者、文件所有者、超级用户 root。

      为一个目录设置SUID和SGID位可以使用下面的命令:

      $ chmod ug+s dirname
      $ ls -l
      drwsr-sr-x 2 root root  4096 Jun 19 06:45 dirname
      $
      

      Linux环境变量

      在Linux中,环境变量是一个很重要的概念。环境变量可以由系统、用户、Shell以及其他程序来设定。

      变量就是一个可以被赋值的字符串,赋值范围包括数字、文本、文件名、设备以及其他类型的数据。

      下面的例子,我们将为变量 TEST 赋值,然后使用 echo 命令输出:

      $TEST="Linux Programming"
      $echo $TEST
      Linux Programming
      

      注意:变量赋值时前面不能加 $ 符号,变量输出时必须要加 $ 前缀。退出 Shell 时,变量将消失。

      登录系统后,Shell会有一个初始化的过程,用来设置环境变量。这个阶段,Shell会读取 /etc/profile 和 .profile 两个文件,过程如下:

    • Shell首先检查 /etc/profile 文件是否存在,如果存在,就读取内容,否则就跳过,但是不会报错。
    • 然后检查你的主目录(登录目录)中是否存在 .profile 文件,如果存在,就读取内容,否则就跳过,也不会报错。


      读取完上面两个文件,Shell就会出现 $ 命令提示符:

      $
      

      出现这个提示符,就可以输入命令并调用相应的程序了。

      注意:上面是Bourne Shell的初始化过程,bash 和 ksh 在初始化过程中还会检查其他文件。

      .profile文件

      /etc/profile文件包含了通用的Shell初始化信息,由Linux管理员维护,一般用户无权修改。

      但是你可以修改主目录下的 .profile 文件,增加一些"私人定制"初始化信息,包括:

    • 设置默认终端类型和外观样式;
    • 设置 Shell 命令查找路径,即PATH变量;
    • 设置命令提示符。


      找到主目录下的 .profile 文件,使用 vi 编辑器打开并查看内容。

      设置终端类型

      一般情况下,我们使用的终端是由 login 或 getty 程序设置的,可能会不符合我们的习惯。

      对于没有使用过的终端,可能会比较生疏,不习惯命令的输出样式,交互起来略显吃力。所以,一般用户会将终端设置成下面的类型:

      $TERM=vt100
      $
      

      vt100 是 virtual terminate 100 的缩写。虚拟终端是一种假的终端,真正有自己的显示器和键盘的终端,会通过特殊电缆(如串口)连到计算机主机。vt100 是被绝大多数Linux系统所支持的一种虚拟终端规范,常用的还有ansi、xterm等。

      设置PATH变量

      在命令提示符下输入一个命令时,Shell 会根据 PATH 变量来查找该命令对应的程序,PATH变量指明了这些程序所在的路径。

      一般情况下PATH变量的设置如下:

      $PATH=/bin:/usr/bin
      $
      

      多个路径使用冒号(:)分隔。如果用户输入的命令在PATH设置的路径下没有找到,就会报错,例如:

      $hello
      hello: not found
      $
      

      PS1和PS2变量

      PS1变量用来保存命令提示符,可以随意修改,如果你不习惯使用 $ 作为提示符,也可以改成其他字符。PS1变量被修改后,提示符会立即改变。

      例如,把命令提示符设置成'=>':

      $PS1='=>'
      =>
      =>
      =>
      

      也可以将提示信息设置成当前目录,例如:

      =>PS1="[\u@\h \w]\$"
      [root@ip-72-167-112-17 /var/www/tutorialspoint/Linux]$
      [root@ip-72-167-112-17 /var/www/tutorialspoint/Linux]$
      

      命令提示信息包含了用户名、主机名和当前目录。

      下表中的转义字符可以被用作PS1的参数,丰富命令提示符信息。

      转义字符

      描述

      \t

      当前时间,格式为 HH:MM:SS

      \d

      当前日期,格式为Weekday Month Date

      \n

      换行

      \W

      当前所在目录

      \w

      当前所在目录的完整路径

      \u

      用户名

      \h

      主机名(IP地址)

      #

      输入的命令的个数,每输入一个新的命令就会加1

      \$

      如果是超级用户 root,提示符为#,否则为$。


      你可以在每次登录的时候修改提示符,也可以在 .profile 文件中增加 PS1 变量,这样每次登录时会自动修改提示符。

      如果用户输入的命令不完整,Shell还会使用第二提示符来等待用户完成命令的输入。默认的第二命令提示符是 >,保存在 PS2 变量,可以随意修改。

      下面的例子使用默认的第二命令提示符:

      $ echo "this is a
      > test"
      this is a
      test
      $
      

      下面的例子通过PS2变量改变提示符:

      $ PS2="secondary prompt->"
      $ echo "this is a
      secondary prompt->test"
      this is a
      test
      $
      

      常用环境变量

      下表列出了部分重要的环境变量,这些变量可以通过上面提到的方式修改。

      变量

      描述

      DISPLAY

      用来设置将图形显示到何处。

      HOME

      当前用户的主目录。

      IFS

      内部域分隔符。

      LANG

      LANG可以让系统支持多语言。例如,将LANG设为pt_BR,则可以支持(巴西)葡萄牙语。

      PATH

      指定Shell命令的路径。

      PWD

      当前所在目录,即 cd 到的目录。

      RANDOM

      生成一个介于 0 和 32767 之间的随机数。

      TERM

      设置终端类型。

      TZ

      时区。可以是AST(大西洋标准时间)或GMT(格林尼治标准时间)等。

      UID

      以数字形式表示的当前用户ID,shell启动时会被初始化。


      下面的例子中使用了部分环境变量:

      $ echo $HOME
      /root
      ]$ echo $DISPLAY
      
      $ echo $TERM
      xterm
      $ echo $PATH
      /usr/local/bin:/bin:/usr/bin:/home/amrood/bin:/usr/local/bin
      $
      

      Linux打印文件和发送邮件

      通过前面的介绍,相信你对 Linux 的命令和特性有了一个基本的认识,本节将介绍如果打印文件以及发送邮件。

      文件打印

      如果你希望打印文本文件,最好预先处理一下,包括调整边距、设置行高、设置标题等,这样打印出来的文件更加美观,易于阅读。当然,不处理也可以打印,但是可能会比较丑陋。

      大部分的Linux自带了 nroff 和 troff 两个强大的文本格式化工具,不过比较老旧,使用的人很少,有兴趣的读者可以可以自行学习,本教程不再进行深入讲解。

      pr命令

      pr 命令用来将文本文件转换成适合打印的格式,它可以把较大的文件分割成多个页面进行打印,并为每个页面添加标题。

      pr 命令的语法如下:

      pr option(s) filename(s)
      

      pr 命令仅仅改变文件在屏幕上的显示样式和打印输出样式,并不会更改文件本身。下表是 pr 命令的几个选项:

      选项

      说明

      -k

      分成几列打印,默认为1。

      -d

      两倍行距(并不是所有版本的 pr 都有效)。

      -h "header"

      设置每个页面的标题。

      -t

      不打印标题和上下边距。

      -l PAGE_LENGTH

      每页显示多少行。默认是每个页面一共66行,文本占56行。

      -o MARGIN

      每行缩进的空格数。

      -w PAGE_WIDTH

      多列输出时,设置页面宽度,默认是72个字符。


      例如,food 文件包含了很多食品的名字,使用 pr 命令分成两列打印,并设置每页的标题为"Restaurants"。

      首先查看文件内容:

      $cat food
      Sweet Tooth
      Bangkok Wok
      Mandalay
      Afghani Cuisine
      Isle of Java
      Big Apple Deli
      Sushi and Sashimi
      Tio Pepe's Peppers
      ........
      $
      

      然后使用 pr 命令打印:

      $pr -2 -h "Restaurants" food
      Nov  7  9:58 1997  Restaurants   Page 1
      
      Sweet Tooth              Isle of Java
      Bangkok Wok              Big Apple Deli
      Mandalay                 Sushi and Sashimi
      Afghani Cuisine          Tio Pepe's Peppers
      ........
      $
      

      lp和lpr命令

      lp 和 lpr 命令将文件传送到打印机进行打印。使用 pr 命令将文件格式化后就可以使用这两个命令来打印。

      打印机一般由系统管理员来设置,下面的例子使用默认的打印机打印food文件:

      $lp food
      request id is laserp-525  (1 file)
      $
      

      命令成功执行会返回一个表示打印任务的ID,通过这个ID可以取消打印或者查看打印状态。

      如果你希望打印多份文件,可以使用 lp 的 -nNum 选项,或者 lpr 命令的 -Num 选项。Num 是一个数字,可以随意设置。

      如果系统连接了多台打印机,可以使用 lp 命令的 -dprinter 选项,或者 lpr 命令的 -Pprinter 选项来选择打印机。printer 为打印机名称。

      lpstat 和 lpq 命令

      lpstat 命令可以查看打印机的缓存队列(有多少个文件等待打印),包括任务ID、所有者、文件大小、请求时间和请求状态。

      提示:等待打印的文件会被放到打印机的的缓存队列中。

      例如,使用 lpstat -o 命令查看打印机中所有等待打印的文件,包括你自己的:

      $lpstat -o
      laserp-573  john  128865  Nov 7  11:27  on laserp
      laserp-574  grace  82744  Nov 7  11:28
      laserp-575  john   23347  Nov 7  11:35
      $
      

      lpstat -o 命令按照打印顺序输出队列中的文件。

      lpq 命令显示的信息与 lpstat -o 稍有差异:

      $lpq
      laserp is ready and printing
      Rank   Owner      Job  Files                  Total Size
      active john       573  report.ps              128865 bytes
      1st    grace      574  ch03.ps ch04.ps        82744 bytes
      2nd    john       575  standard input         23347 bytes
      $
      

      第一行为打印机的状态。如果打印机无法使用或者纸被用完,将会输出其他信息。

      cancel 和 lprm 命令

      cancel 和 lprm 分别用来终止 lp 和 lpr 的打印请求。使用这两个命令,需要指定ID(由 lp 或 lpq 返回)或打印机名称。

      例如,通过ID取消打印请求:

      $cancel laserp-575
      request "laserp-575" cancelled
      $
      

      如果希望取消正在打印的文件,那么可以不指定ID,仅仅指定打印机名称即可:

      $cancel laserp
      request "laserp-573" cancelled
      $
      


      lprm 命令用来取消当前用户的正在等待打印的文件,使用任务号作为参数可以取消指定文件,使用横线(-)作为参数可以取消所有文件。

      例如,取消575号打印任务:

      $lprm 575
      dfA575diamond dequeued
      cfA575diamond dequeued
      $
      

      lprm 会返回被取消的文件名。

      发送邮件

      可以使用mail命令发送和接收邮件,语法如下:

      $mail [-s subject] [-c cc-addr] [-b bcc-addr] to-addr
      

      每个选项的含义如下:

      选项

      描述

      -s

      邮件标题。

      -c

      要发送的用户,多个用户以逗号(,)分隔。

      -b

      需要密件发送(密送)的用户,多个用户以逗号(,)分隔。


      例如,向admin@yahoo.com发送邮件:

      $mail -s "Test Message" admin@yahoo.com
      Hello everyone, 
      this is Linux tutorial and url is http://see.xidian.edu.cn/cpp/linux/.
      Cc: 
      

      第一行是输入的命令,-s表示邮件的主题,后面的admin@yahoo.com则是邮件的接收人,输入完这行命令后回车,会进入邮件正文的编写,你可以输入任何文字,比如上面的两行。输入完邮件正文,需要按CTRL+D结束输入,此时会提示你输入Cc地址,即邮件抄送地址,没有直接回车就完成了邮件的发送。

      也可以通过重定向操作符 < 来发送文件:

      $mail -s "Report 05/06/07" admin@yahoo.com < demo.txt
      

      通过上面的命令,就可以把demol.txt文件的内容作为邮件的内容发送给admin@yahoo.com了。

      接收邮件不需要任何参数:

      $mail
      no email
      

      Linux管道和过滤器

      有时候,我们可以把两个命令连起来使用,一个命令的输出作为另一个命令的输入,这就叫做管道。为了建立管道,需要在两个命令之间使用竖线(|)连接。

      管道是Linux进程之间一种重要的通信机制;除了管道,还有共享内存、消息队列、信号、套接字(socket) 等进程通信机制。

      管道使用竖线(|)将两个命令隔开,竖线左边命令的输出就会作为竖线右边命令的输入。连续使用竖线表示第一个命令的输出会作为第二个命令的输入,第二个命令的输出又会作为第三个命令的输入,依此类推。

      能够接受数据,过滤(处理或筛选)后再输出的工具,称为过滤器

      grep命令

      grep 是一个强大的文本搜索工具,可以使用正则表达式,并返回匹配的行,语法为:

      $grep pattern file(s)
      

      "grep"源于 ed(Linux的一个行文本编辑器)的 g/re/p 命令,g/re/p 是"globally search for a regular expression and print all lines containing it"的缩写,意思是使用正则表达式进行全局检索,并把匹配的行打印出来。

      正则表达式是一个包含了若干特殊字符的字符串,每个字符都有特殊含义,可以用来匹配文本,更多信息请查看正则表达式教程

      grep 可以看做是一个过滤器,如果没有为 grep 指定要检索的文件,那么它会从标准输入设备(一般是键盘)读取;其他过滤器也是如此。

      grep 命令最简单的使用就是检索包含固定字符的文本。

      例如,在管道中使用 grep 命令,只允许包含指定字符的行输出到显示器:

      $ls -l | grep "Aug"
      -rw-rw-rw-   1 john  doc     11008 Aug  6 14:10 ch02
      -rw-rw-rw-   1 john  doc      8515 Aug  6 15:30 ch07
      -rw-rw-r--   1 john  doc      2488 Aug 15 10:51 intro
      -rw-rw-r--   1 carol doc      1605 Aug 23 07:35 macros
      $
      

      grep 命令有很多选项:

      选项

      说明

      -v

      反转查询,输出不匹配的行。例如,grep -v "test" demo.txt 将输出不包含"test"的行。

      -n

      输出匹配的行以及行号。

      -l

      输出匹配的行所在的文件名。

      -c

      输出匹配的总行数。

      -i

      不区分大小写进行匹配。


      下面我们使用正则表达式来匹配这样的行:包含字符"carol",然后包含任意数目(含零个)的其他字符,最后还要包含"Aug"。

      使用 -i 选项进行不区分大小写的匹配:

      $ls -l | grep -i "carol.*aug"
      -rw-rw-r--   1 carol doc      1605 Aug 23 07:35 macros
      $
      

      sort命令

      sort 命令在 Linux 中非常有用,它将文件中的各行按字母或数进行排序。sort命令既可以从特定的文件,也可以从stdin获取输入。

      例如,对 foot 文件的各行进行排序:

      $sort food
      Afghani Cuisine
      Bangkok Wok
      Big Apple Deli
      Isle of Java
      Mandalay
      Sushi and Sashimi
      Sweet Tooth
      Tio Pepe's Peppers
      $
      

      通过下面的选项可以控制排序规则:

      选项

      描述

      -n

      按照数字大小排序,例如,10会排在2后面;-n 选项会忽略空格或 tab缩进。

      -r

      降序排序。sort 默认是升序排序。

      -f

      不区分大小写。

      +x

      对第x列(从0开始)进行排序。


      下面的例子通过管道将 ls、grep 和 sort 命令连起来使用,过滤包含"Aug"的行,并按照文件大小排序:

      $ls -l | grep "Aug" | sort +4n
      -rw-rw-r--  1 carol doc      1605 Aug 23 07:35 macros
      -rw-rw-r--  1 john  doc      2488 Aug 15 10:51 intro
      -rw-rw-rw-  1 john  doc      8515 Aug  6 15:30 ch07
      -rw-rw-rw-  1 john  doc     11008 Aug  6 14:10 ch02
      $
      

      上面的命令,对当前目录中八月份修改的文件按照大小排序;+4n 表示对第5列按照数字大小排序。

      pg和more命令

      如果文件内容过多,全部显示会很乱,可以使用 pg 和 more 命令分页显示,每次只显示一屏。

      例如,通过管道,使用more命令显示目录中的文件:

      $ls -l | grep "Aug" | sort +4n | more
      -rw-rw-r--  1 carol doc      1605 Aug 23 07:35 macros
      -rw-rw-r--  1 john  doc      2488 Aug 15 10:51 intro
      -rw-rw-rw-  1 john  doc      8515 Aug  6 15:30 ch07
      -rw-rw-r--  1 john  doc     14827 Aug  9 12:40 ch03
      .
      .
      .
      -rw-rw-rw-  1 john  doc     16867 Aug  6 15:56 ch05
      --More--(74%)
      

      如上,一次只显示一屏文本,显示满后,停下来,并提示已显示全部内容的百分比,按空格键(space)可以查看下一屏,按 b 键可以查看上一屏。

      Linux进程管理

      当我们运行程序时,Linux会为程序创建一个特殊的环境,该环境包含程序运行需要的所有资源,以保证程序能够独立运行,不受其他程序的干扰。这个特殊的环境就称为进程。

      每个 Linux 命令都与系统中的程序对应,输入命令,Linux 就会创建一个新的进程。例如使用 ls 命令遍历目录中的文件时,就创建了一个进程。

      简而言之,进程就是程序的实例。

      系统通过一个五位数字跟踪程序的运行状态,这个数字称为 pid 或进程ID。每个进程都拥有唯一的 pid。

      理论上,五位数字是有限的,当数字被用完时,下一个 pid 就会重新开始,所以 pid 最终会重复。但是,两个 pid 一样的进程不能同时存在,因为Linux会使用 pid 来跟踪程序的运行状态。

      创建进程

      有两种方式来创建进程:前台进程和后台进程。

      前台进程

      默认情况下,用户创建的进程都是前台进程;前台进程从键盘读取数据,并把处理结果输出到显示器。

      我们可以看到前台进程的运行过程。例如,使用 ls 命令来遍历当前目录下的文件:

      $ls ch*.doc
      ch01-1.doc   ch010.doc  ch02.doc    ch03-2.doc
      ch04-1.doc   ch040.doc  ch05.doc    ch06-2.doc
      ch01-2.doc   ch02-1.doc
      

      这个程序就运行在前台,它会直接把结果输出到显示器。如果 ls 命令需要数据(实际上不需要),那么它会等待用户从键盘输入。

      当程序运行在前台时,由于命令提示符($)还未出现,用户不能输入其他命令;即使程序需要运行很长时间,也必须等待程序运行结束才能输入其他命令。

      后台进程

      后台进程与键盘没有必然的关系。当然,后台进程也可能会等待键盘输入。

      后台进程的优点是不必等待程序运行结束就可以输入其他命令。

      创建后台进程最简单的方式就是在命令的末尾加 &,例如:

      $ls ch*.doc &
      ch01-1.doc   ch010.doc  ch02.doc    ch03-2.doc
      ch04-1.doc   ch040.doc  ch05.doc    ch06-2.doc
      ch01-2.doc   ch02-1.doc
      

      如果 ls 命令需要输入(实际上不需要),那么它会暂停,直到用户把它调到前台并从键盘输入数据才会继续运行。

      查看正在运行的进程

      可以使用 ps 命令查看进程的运行状态,包括后台进程,例如:

      $ps
      PID       TTY      TIME        CMD
      18358     ttyp3    00:00:00    sh
      18361     ttyp3    00:01:31    abiword
      18789     ttyp3    00:00:00    ps
      

      还可以结合 -f 选项查看更多信息,f 是 full 的缩写,例如:

      $ps -f
      UID      PID  PPID C STIME    TTY   TIME CMD
      amrood   6738 3662 0 10:23:03 pts/6 0:00 first_one
      amrood   6739 3662 0 10:22:54 pts/6 0:00 second_one
      amrood   3662 3657 0 08:10:53 pts/6 0:00 -ksh
      amrood   6892 3662 4 10:51:50 pts/6 0:00 ps -f
      

      每列的含义如下:

      描述

      UID

      进程所属用户的ID,即哪个用户创建了该进程。

      PID

      进程ID。

      PPID

      父进程ID,创建该进程的进程称为父进程。

      C

      CPU使用率。

      STIME

      进程被创建的时间。

      TTY

      与进程有关的终端类型。

      TIME

      进程所使用的CPU时间。

      CMD

      创建该进程的命令。


      ps 命令还有其他一些选项:

      选项

      说明

      -a

      显示所有用户的所有进程。

      -x

      显示无终端的进程。

      -u

      显示更多信息,类似于 -f 选项。

      -e

      显示所有进程。

      终止进程

      当进程运行在前台时,可以通过 kill 命令或 Ctrl+C 组合键来结束进程。

      如果进程运行在后台,那么首先要通过 ps 命令来获取进程ID,然后使用 kill 命令"杀死"进程,例如:

      $ps -f
      UID      PID  PPID C STIME    TTY   TIME CMD
      amrood   6738 3662 0 10:23:03 pts/6 0:00 first_one
      amrood   6739 3662 0 10:22:54 pts/6 0:00 second_one
      amrood   3662 3657 0 08:10:53 pts/6 0:00 -ksh
      amrood   6892 3662 4 10:51:50 pts/6 0:00 ps -f
      $kill 6738
      Terminated
      

      如上所示,kill 命令终结了 first_one 进程。

      如果进程忽略 kill 命令,那么可以通过 kill -9 来结束:

      $kill -9 6738
      Terminated
      

      父进程和子进程

      每个 Linux 进程会包含两个进程ID:当前进程ID(pid)和父进程ID(ppid)。可以暂时认为所有的进程都有父进程。

      由用户运行的大部分命令都将 Shell 作为父进程,使用 ps -f 命令可以查看当前进程ID和父进程ID。

      僵尸进程和孤儿进程

      正常情况下,子进程被终止时会通过 SIGCHLD 信号通知父进程,父进程可以做一些清理工作或者重新启动一个新的进程。但在某些情况下,父进程会在子进程之前被终止,那么这些子进程就没有了"父亲",被称为孤儿进程

      init 进程会成为所有孤儿进程的父进程。init 的 pid 为1,是Linux系统的第一个进程,也是所有进程的父进程。

      如果一个进程被终止了,但是使用 ps 命令仍然可以查看该进程,并且状态为 Z,那么这就是一个僵尸进程。僵尸进程虽然被终止了,但是仍然存在于进程列表中。一般僵尸进程很难杀掉,你可以先杀死他们的父进程,让他们变成孤儿进程,init 进程会自动清理僵尸进程。

      常驻进程

      常驻进程一般是系统级进程,以 root 权限运行在后台,可以处理其他进程的请求。

      常驻进程没有终端,不能访问 /dev/tty 文件,如果使用 ps -ef 查看该进程,tty 这一列会显示问号(?)。

      更确切地说,常驻进程通常运行在后台,等待指定事件发生,例如打印进程是一个常驻进程,它会等待用户输入打印相关的命令并进行处理。

      top命令

      top 命令是一个很有用的工具,它可以动态显示正在运行的进程,还可以按照指定条件对进程进行排序,与Windows的任务管理器类似。

      top 命令可以显示进程的很多信息,包括物理内存、虚拟内存、CPU使用率、平均负载以及繁忙的进程等。例如:

      $top
      

      这里仅给出一个示意图,读者最好亲自运行一下:

      任务和进程

      任务(task)是最抽象的,是一个一般性的术语,指由软件完成的一个活动。一个任务既可以是一个进程,也可以是多个进程。简而言之,它指的是一系列共同达到某一目的的操作。例如,读取数据并将数据放入内存中。这个任务可以由一个进程来实现,也可以由多个进程来实现。  每个任务都有一个数字表示的任务号。
        
      进程(process)常常被定义为程序的执行。可以把一个进程看成是一个独立的程序,在内存中有其完备的数据空间和代码空间。一个进程所拥有的数据和变量只属于它自己。

      jobs 命令可以用来查看系统中正在运行的任务,包括后台运行的任务。该命令可以显示任务号及其对应的进程ID。一个任务可以对应于一个或者多个进程号。

      jobs 命令的 -l 选项可以查看当前任务包含的进程ID:

      $jobs -l
      [1] + 1903 running                 ls ch*.doc &
      $
      

      其中,第一列表示任务号,第二列表示任务对应的进程ID,第三列表示任务的运行状态,第四列表示启动任务的命令。

      前台任务和后台任务的切换

      fg 命令可以将后台任务调到前台,语法为:

      $fg %jobnumber
      

      jobnumber 是通过 jobs 命令获取的后台任务的的序号,注意不是pid。如果后台只有一个任务,可以不指定 jobnumber。

      bg 命令可以将后台暂停的任务,调到前台继续运行,语法为:

      $bg %jobnumber
      

      jobnumber 同样是通过 jobs 命令获取的后台任务的的序号,注意不是pid。如果前台只有一个任务,可以不指定 jobnumber。

      如果希望将当前任务转移到后台,可以先 Ctrl+z 暂停任务,再使用 bg 命令。任务转移到后台可以空出终端,继续输入其他命令。

      Linux网络通信工具

      现在是一个互联网的时代,你不可避免的要和其他用户进行远程交流,连接到远程主机。

      ping 命令

      ping 命令会向网络上的主机发送应答请求,根据响应信息可以判断远程主机是否可用。

      ping 命令的语法:

      $ping hostname or ip-address
      

      如果网络畅通,很快就可以看到响应信息。

      例如,检测是否可以连接到谷歌的主机:

      $ping google.com
      PING google.com (74.125.67.100) 56(84) bytes of data.
      64 bytes from 74.125.67.100: icmp_seq=1 ttl=54 time=39.4 ms
      64 bytes from 74.125.67.100: icmp_seq=2 ttl=54 time=39.9 ms
      64 bytes from 74.125.67.100: icmp_seq=3 ttl=54 time=39.3 ms
      64 bytes from 74.125.67.100: icmp_seq=4 ttl=54 time=39.1 ms
      64 bytes from 74.125.67.100: icmp_seq=5 ttl=54 time=38.8 ms
      --- google.com ping statistics ---
      22 packets transmitted, 22 received, 0% packet loss, time 21017ms
      rtt min/avg/max/mdev = 38.867/39.334/39.900/0.396 ms
      $
      

      如果主机没有响应,可以看到类似下面的信息:

      $ping giiiiiigle.com
      ping: unknown host giiiiigle.com
      $
      

      ftp 工具

      ftp 是 File Transfer Protocol 的缩写,称为文件传输协议。通过 ftp 工具,能够将文件上传到远程服务器,也可以从远程服务器下载文件。

      ftp 工具有自己的命令(类似Linux命令),可以:

    • 连接并登录远程主机;
    • 查看目录,遍历目录下的文件;
    • 上传或下载文件,包括文本文件、二进制文件等。


      ftp 命令的用法如下:

      $ftp hostname or ip-address
      

      接下来会提示你输入用户名和密码,验证成功后会进入主目录,然后就可以使用 ftp 工具的命令进行操作了。

      ftp命令

      说明

      put filename

      将本地文件上传到远程主机。

      get filename

      将远程文件下载到本地。

      mput file list

      将多个本地文件上传到远程主机。

      mget file list

      将多个远程文件下载到本地。

      prompt off

      关闭提示。默认情况下,使用 mput 或 mget 命令会不断提示你确认文件的上传或下载。

      prompt on

      打开提示。

      dir

      列出远程主机当前目录下的所有文件。

      cd dirname

      改变远程主机目录。

      lcd dirname

      改变本地目录。

      quit

      退出登录。


      注意,所有的上传和下载都是针对本地主机和远程主机的当前目录,如果你希望上传指定目录下的文件,首先要 cd 到该目录,然后才能上传。

      ftp 工具使用举例:

      $ftp amrood.com
      Connected to amrood.com.
      220 amrood.com FTP server (Ver 4.9 Thu Sep 2 20:35:07 CDT 2009)
      Name (amrood.com:amrood): amrood
      331 Password required for amrood.
      Password:
      230 User amrood logged in.
      ftp> dir
      200 PORT command successful.
      150 Opening data connection for /bin/ls.
      total 1464
      drwxr-sr-x   3 amrood   group       1024 Mar 11 20:04 Mail
      drwxr-sr-x   2 amrood   group       1536 Mar  3 18:07 Misc
      drwxr-sr-x   5 amrood   group        512 Dec  7 10:59 OldStuff
      drwxr-sr-x   2 amrood   group       1024 Mar 11 15:24 bin
      drwxr-sr-x   5 amrood   group       3072 Mar 13 16:10 mpl
      -rw-r--r--   1 amrood   group     209671 Mar 15 10:57 myfile.out
      drwxr-sr-x   3 amrood   group        512 Jan  5 13:32 public
      drwxr-sr-x   3 amrood   group        512 Feb 10 10:17 pvm3
      226 Transfer complete.
      ftp> cd mpl
      250 CWD command successful.
      ftp> dir
      200 PORT command successful.
      150 Opening data connection for /bin/ls.
      total 7320
      -rw-r--r--   1 amrood   group       1630 Aug  8 1994  dboard.f
      -rw-r-----   1 amrood   group       4340 Jul 17 1994  vttest.c
      -rwxr-xr-x   1 amrood   group     525574 Feb 15 11:52 wave_shift
      -rw-r--r--   1 amrood   group       1648 Aug  5 1994  wide.list
      -rwxr-xr-x   1 amrood   group       4019 Feb 14 16:26 fix.c
      226 Transfer complete.
      ftp> get wave_shift
      200 PORT command successful.
      150 Opening data connection for wave_shift (525574 bytes).
      226 Transfer complete.
      528454 bytes received in 1.296 seconds (398.1 Kbytes/s)
      ftp> quit
      221 Goodbye.
      $
      

      telnet工具

      Telnet 工具可以让我们连接并登录到远程计算机。

      一旦连接到了远程计算机,就可以在上面进行各种操作了,例如:

      C:>telnet amrood.com
      Trying...
      Connected to amrood.com.
      Escape character is '^]'.
      
      login: amrood
      amrood's Password:
      *****************************************************
      *                                                   *
      *                                                   *
      *            WELCOME TO AMROOD.COM                  *
      *                                                   *
      *                                                   *
      *****************************************************
      
      Last unsuccessful login: Fri Mar  3 12:01:09 IST 2009
      Last login: Wed Mar  8 18:33:27 IST 2009 on pts/10
      
         {  do your work }
      
      $ logout
      Connection closed.
      C:>
      

      finger工具

      finger 可以让我们查看本地主机或远程主机上的用户信息。有些系统为了安全会禁用 finger 命令。

      例如,查看本机在线用户:

      $ finger
      Login     Name       Tty      Idle  Login Time   Office
      amrood               pts/0          Jun 25 08:03 (62.61.164.115)
      

      查看本机指定用户的信息:

      $ finger amrood
      Login: amrood                           Name: (null)
      Directory: /home/amrood                 Shell: /bin/bash
      On since Thu Jun 25 08:03 (MST) on pts/0 from 62.61.164.115
      No mail.
      No Plan.
      

      查看远程主机上的在线用户:

      $ finger @avtar.com
      Login     Name       Tty      Idle  Login Time   Office
      amrood               pts/0          Jun 25 08:03 (62.61.164.115)
      

      查看远程主机上某个用户的信息:

      $ finger amrood@avtar.com
      Login: amrood                           Name: (null)
      Directory: /home/amrood                 Shell: /bin/bash
      On since Thu Jun 25 08:03 (MST) on pts/0 from 62.61.164.115
      No mail.
      No Plan.
      

      10分钟掌握Linux vi编辑器常见命令的使用,最简单的vi编辑器教程

      Linux下的文本编辑器有很多种,vi 是最常用的,也是各版本Linux的标配。注意,vi 仅仅是一个文本编辑器,可以给字符着色,可以自动补全,但是不像 Windows 下的 word 有排版功能。

      vi 是十年磨一剑的产品,虽然命令繁多,并且大多数功能都是依靠键盘输入来完成,但是一旦你熟悉后,会发现 vi 的功能和效率是其他图形界面编辑器无法比拟的。

      Vim 是 Vimproved 的缩写,是 vi 的改进版。在Linux中,vi 被认为是事实上的标准编辑器,因为:

    • 所有版本的 Linux 都带有 vi 编辑器;
    • 占用资源少;
    • 与 ed、ex 等其他编辑器相比,vi 对用户更加友好。


      你可以使用 vi 编辑器编辑现有的文件,也可以创建一个新文件,还能以只读模式打开文本文件。

      进入 vi 编辑器

      可以通过以下方式进入 vi 编辑器:

      命令

      描述

      vi filename

      如果filename存在,则打开;否则会创建一个新文件再打开。

      vi -R filename

      以只读模式(只能查看不能编辑)打开现有文件。

      view filename

      以只读模式打开现有文件。


      例如,使用 vi 编辑器创建一个新文件并打开:

      $vi testfile
      |
      ~
      ~
      ~
      ~
      ~
      ~
      ~
      ~
      ~
      ~
      ~
      ~
      "testfile" [New File]
      

      竖线(|)代表光标的位置;波浪号(~)代表该行没有任何内容。如果没有 ~,也看不到任何内容,那说明这一行肯定是有空白字符(空格、tab 缩进、换行符等)或不可见字符。

      工作模式

      进一步了解 vi 之前先来了解一下 vi 的工作模式,vi 有三种工作模式:

      1) 普通模式

      由Shell进入vi编辑器时,首先进入普通模式。在普通模式下,从键盘输入任何字符都被当作命令来解释。普通模式下没有任何提示符,输入命令后立即执行,不需要回车,而且输入的字符不会在屏幕上显示出来。

      普通模式下可以执行命令、保存文件、移动光标、粘贴复制等。

      2) 编辑模式

      编辑模式主要用于文本的编辑。该模式下用户输入的任何字符都被作为文件的内容保存起来,并在屏幕上显示出来。

      3) 命令模式

      命令模式下,用户可以对文件进行一些高级处理。尽管普通模式下的命令可以完成很多功能,但要执行一些如字符串查找、替换、显示行号等操作还是必须要进入命令模式。

      注意:有些教程中称有两种工作模式,是把命令模式合并到普通模式。

      工作模式切换:

    • 在普通模式下输入 i(插入)、c(修改)、o(另起一行) 命令时进入编辑模式;按 esc 键退回到普通模式。
    • 在普通模式下输入冒号(:)可以进入命令模式。输入完命令按回车,命令执行完后会自动退回普通模式。


      提示:如果不确定当前处于哪种模式,按两次 Esc 键将回到普通模式。

      退出 vi 编辑器

      一般在命令模式下退出 vi 编辑器。

      退出命令

      说明

      q

      如果文件未被修改,会直接退回到Shell;否则提示保存文件。

      q!

      强行退出,不保存修改内容。

      wq

      w 命令保存文件,q 命令退出 vi,合起来就是保存并退出。

      ZZ

      保存并退出,相当于 wq,但是更加方便。


      退出之前,你也可以在 w 命令后面指定一个文件名,将文件另存为新文件,例如:

      w filename2
      

      将当前文件另存为 filename2。

      注意:vi 编辑文件时,用户的操作都是基于缓冲区中的副本进行的。如果退出时没有保存到磁盘,则缓冲区中的内容就会被丢失。

      移动光标

      为了不影响文件内容,必须在普通模式(按两次 Esc 键)下移动光标。使用下表中的命令每次可以移动一个字符:

      命令

      描述

      k

      向上移动光标(移动一行)

      j

      向下移动光标(移动一行)

      h

      向左移动光标(移动一个字符)

      l

      向右移动光标(移动一个字符)


      两点提醒:

    • vi 是区分大小写的,输入命令时注意不要锁定大写。
    • 可以在命令前边添加一个数字作为前缀,例如,2j 将光标向下移动两行。


      当然,还有很多其他命令来移动光标,不过记住,一定要在普通模式(按两次 Esc 键)下。

      用来移动光标的命令

      命令

      说明

      0 或 |

      将光标定位在一行的开头。

      $

      将光标定位在一行的末尾。

      w

      定位到下一个单词。

      b

      定位到上一个单词。

      (

      定位到一句话的开头,句子是以 ! . ? 三种符号来界定的。

      )

      定位到一句话的结尾。

      {

      移动到段落开头。&&&&&&

      }

      移动到段落结束。&&&&&&&&&

      [[

      回到段落的开头处。&&&&&&&&&&

      ]]

      向前移到下一个段落的开头处。&&&&&&&&&&

      n|

      移动到第 n 列(当前行)。

      1G

      移动到文件第一行。

      G

      移动到文件最后一行。

      nG

      移动到文件第 n 行。

      :n

      移动到文件第 n 行。

      H

      移动到屏幕顶部。

      nH

      移动到距离屏幕顶部第 n 行的位置。

      M

      移动到屏幕中间。

      L

      移动到屏幕底部。

      nL

      移动到距离屏幕底部第 n 行的位置。

      :x

      x 是一个数字,表示移动到行号为 x 的行。

      控制命令

      有一些控制命令可以与 Ctrl 键组合使用,如下:

      命令

      描述

      CTRL+d

      向前滚动半屏

      CTRL+f

      向前滚动全屏

      CTRL+u

      向后滚动半屏

      CTRL+b

      向后滚动整屏

      CTRL+e

      向上滚动一行

      CTRL+y

      向下滚动一行

      CTRL+I

      刷新屏幕

      编辑文件

      切换到编辑模式下才能编辑文件。有很多命令可以从普通模式切换到编辑模式,如下所示:

      命令

      描述

      i

      在当前光标位置之前插入文本

      I

      在当前行的开头插入文本

      a

      在当前光标位置之后插入文本

      A

      在当前行的末尾插入文本

      o

      在当前位置下面创建一行

      O

      在当前位置上面创建一行

      删除字符

      下面的命令,可以删除文件中的字符或行:

      命令

      说明

      x

      删除当前光标下的字符

      X

      删除光标前面的字符

      dw

      删除从当前光标到单词结尾的字符

      d^

      删除从当前光标到行首的字符

      d$

      删除从当前光标到行尾的字符

      D

      删除从当前光标到行尾的字符

      dd

      删除当前光标所在的行


      可以在命令前面添加一个数字前缀,表示重复操作的次数,例如,2x  表示连续两次删除光标下的字符,2dd 表示连续两次删除光标所在的行。

      建议各位读者多加练习上面的命令,再进一步深入学习。

      修改文本

      如果你希望对字符、单词或行进行修改,可以使用下面的命令:

      命令

      描述

      cc

      删除当前行,并进入编辑模式。

      cw

      删除当前字(单词),并进入编辑模式。

      r

      替换当前光标下的字符。

      R

      从当前光标开始替换字符,按 Esc 键退出。

      s

      用输入的字符替换当前字符,并进入编辑模式。

      S

      用输入的文本替换当前行,并进入编辑模式。

      粘贴复制

      vi 中的复制粘贴命令:

      命令

      描述

      yy

      复制当前行

      nyy

      复制n行

      yw

      复制一个字(单词)

      nyw

      复制n行

      p

      将复制的文本粘贴到光标后面

      P

      将复制的文本粘贴到光标前面

      高级命令

      下面的一些命令虽然看起来有些古怪,但是会让你的工作更有效率,如果你是 vi 重度用户,就了解一下吧。

      命令

      说明

      J

      将当前行和下一行连接为一行

      <<

      将当前行左移一个单位(一个缩进宽度)

      >>

      将当前行右移一个单位(一个缩进宽度)

      ~

      改变当前字符的大小写

      ^G

      Ctrl+G组合键可以显示当前文件名和状态

      U

      撤销对当前行所做的修改

      u

      撤销上次操作,再次按 'u' 恢复该次操作

      :f

      以百分号(%)的形式显示当前光标在文件中的位置、文件名和文件的总行数

      :f filename

      将文件重命名为 filename

      :w filename

      保存修改到 filename

      :e filename

      打开另一个文件名为 filename 的文件

      :cd dirname

      改变当前工作目录到 dirname

      :e #

      在两个打开的文件之间进行切换

      :n

      如果用 vi 打开了多个文件,可以使用 :n 切换到下一个文件

      :p

      如果用 vi 打开了多个文件,可以使用 :n 切换到上一个文件

      :N

      如果用 vi 打开了多个文件,可以使用 :n 切换到上一个文件

      :r file

      读取文件并在当前行的后边插入

      :nr file

      读取文件并在第 n 行后边插入

      文本查找

      如果希望进行全文件搜索,可以在普通模式(按两次 Esc 键)下输入 / 命令,这时状态栏(最后一行)出现"/"并提示输入要查找的字符串,回车即可。

      / 命令是向下查找,如果希望向上查找,可以使用 ? 命令。

      这时,输入 n 命令可以按相同的方向继续查找,输入 N 命令可以按相反的方向继续查找。

      搜索的字符串中可以包含一些有特殊含义的字符,如果希望搜索这些字符本身,需要在前面加反斜杠(\)。

      部分特殊字符列表

      字符

      说明

      ^

      匹配一行的开头

      .

      匹配一个字符

      *

      匹配0个或多个字符

      $

      匹配一行的结尾

      [ ]

      匹配一组字符


      如果希望搜索某行中的单个字符,可以使用 f 或 F 命令,f 向上搜索,F 向下搜索,并且会把光标定位到匹配的字符。

      也可以使用 t 或 T 命令:t 命令向上搜索,并把光标定位到匹配字符的前面;T 命令向下搜索,并把光标定位到匹配字符的后面。

      set 命令

      set 命令可以对 vi 编辑器进行一些设置。使用 set 命令需要进入命令模式。

      :set 命令选项

      命令

      说明

      :set ic

      搜索时忽略大小写。

      :set ai

      设置自动缩进(自动对齐)。

      :set noai

      取消自动缩进(自动对齐)。

      :set nu

      显示行号。

      :set sw

      设置缩进的空格数,例如,将缩进空格数设置为4::set sw=4。

      :set ws

      循环搜索:如果直到文件末尾也没有查找到指定字符,那么会回到开头继续查找。

      :set wm

      设置自动换行,例如,设置距离边际2个字符时换行::set wm=2 。

      :set ro

      将文件类型改为只读。

      :set term

      输出终端类型。

      :set bf

      忽略输入的控制字符,如 BEL(响铃)、BS(退格)、CR(回车)等。

      运行命令

      切换到命令模式,再输入 ! 命令即可运行 Linux 命令。

      例如,保存文件前,如果希望查看该文件是否存在,那么输入

      :! ls
      

      即可列出当前目录下的文件。

      按任意键回到 vi 编辑器。

      文本替换

      切换到命令模式,再输入 s/ 命令即可对文本进行替换。语法为:

      :s/search/replace/g
      

      search 为检索的文本,replace 为要替换的文本,g 表示全局替换。

      几点提示

      vi 编辑器的使用讲解完毕,但是请记住下面几点:

    • 输入冒号(:)进入命令模式,按两次 Esc 键进入普通模式。
    • 命令大小写的含义是不一样的。
    • 必须在编辑模式下才能输入内容。

      Linux文件系统

      文件系统就是分区或磁盘上的所有文件的逻辑集合。

      文件系统不仅包含着文件中的数据而且还有文件系统的结构,所有Linux 用户和程序看到的文件、目录、软连接及文件保护信息等都存储在其中。

      不同Linux发行版本之间的文件系统差别很少,主要表现在系统管理的特色工具以及软件包管理方式的不同,文件目录结构基本上都是一样的。

      文件系统有多种类型,如:

    • ext2 : 早期linux中常用的文件系统;
    • ext3 : ext2的升级版,带日志功能;
    • RAMFS : 内存文件系统,速度很快;
    • iso9660:光盘或光盘镜像;
    • NFS : 网络文件系统,由SUN发明,主要用于远程文件共享;
    • MS-DOS : MS-DOS文件系统;
    • FAT : Windows XP 操作系统采用的文件系统;
    • NTFS : Windows NT/XP 操作系统采用的文件系统。

      分区与目录

      文件系统位于磁盘分区中;一个硬盘可以有多个分区,也可以只有一个分区;一个分区只能包含一个文件系统。

      Linux文件系统与Windows有较大的差别。Windows的文件结构是多个并列的树状结构,最顶部的是不同的磁盘(分区),如 C、D、E、F等。

      Linux的文件结构是单个的树状结构,根目录是"/",其他目录都要位于根目录下。

      每次安装系统的时候我们都会进行分区,Linux下磁盘分区和目录的关系如下:

    • 任何一个分区都必须对应到某个目录上,才能进行读写操作,称为"挂载"。
    • 被挂载的目录可以是根目录,也可以是其他二级、三级目录,任何目录都可以是挂载点。
    • 目录是逻辑上的区分。分区是物理上的区分。
    • 根目录是所有Linux的文件和目录所在的地方,需要挂载上一个磁盘分区。


      下图是常见的目录和分区的对应关系:


      为什么要分区,如何分区?

    • 可以把不同资料,分别放入不同分区中管理,降低风险。
    • 大硬盘搜索范围大,效率低。
    • /home、/var、/usr/local 经常是单独分区,因为经常会操作,容易产生碎片。


      为了便于定位和查找,Linux中的每个目录一般都存放特定类型的文件,下表列出了各种Linux发行版本的常见目录:

      目录

      说明

      /

      根目录,只能包含目录,不能包含具体文件。

      /bin

      存放可执行文件。很多命令就对应/bin目录下的某个程序,例如 ls、cp、mkdir。/bin目录对所有用户有效。

      /dev

      硬件驱动程序。例如声卡、磁盘驱动等,还有如 /dev/null、/dev/console、/dev/zero、/dev/full 等文件。

      /etc

      主要包含系统配置文件和用户、用户组配置文件。

      /lib

      主要包含共享库文件,类似于Windows下的DLL;有时也会包含内核相关文件。

      /boot

      系统启动文件,例如Linux内核、引导程序等。

      /home

      用户工作目录(主目录),每个用户都会分配一个目录。

      /mnt

      临时挂载文件系统。这个目录一般是用于存放挂载储存设备的挂载目录的,例如挂载CD-ROM的cdrom目录。

      /proc

      操作系统运行时,进程(正在运行中的程序)信息及内核信息(比如cpu、硬盘分区、内存信息等)存放在这里。/proc目录伪装的文件系统proc的挂载目录,proc并不是真正的文件系统。

      /tmp

      临时文件目录,系统重启后不会被保存。

      /usr

      /user目下的文件比较混杂,包含了管理命令、共享文件、库文件等,可以被很多用户使用。

      /var

      主要包含一些可变长度的文件,会经常对数据进行读写,例如日志文件和打印队列里的文件。

      /sbin

      和 /bin 类似,主要包含可执行文件,不过一般是系统管理所需要的,不是所有用户都需要。

      常用文件管理命令

      你可以通过下面的命令来管理文件:

      Command

      Description

      cat filename

      查看文件内容。

      cd dirname

      改变所在目录。

      cp file1 file2

      复制文件或目录。

      file filename

      查看文件类型(binary, text, etc)。

      find filename dir

      搜索文件或目录。

      head filename

      显示文件的开头,与tail命令相对。

      less filename

      查看文件的全部内容,可以分页显示,比more命令要强大。

      ls dirname

      遍历目录下的文件或目录。

      mkdir dirname

      创建目录。

      more filename

      查看文件的全部内容,可以分页显示。

      mv file1 file2

      移动文件或重命名。

      pwd

      显示用户当前所在目录。

      rm filename

      删除文件。

      rmdir dirname

      删除目录。

      tail filename

      显示文件的结尾,与head命令相对。

      touch filename

      文件不存在时创建一个空文件,存在时修改文件时间戳。

      whereis filename

      查看文件所在位置。

      which filename

      如果文件在环境变量PATH中有定义,那么显示文件位置。

      df命令

      管理磁盘分区时经常会使用 df (disk free) 命令,df -k 命令可以用来查看磁盘空间的使用情况(以千字节计),例如:

      $df -k
      Filesystem      1K-blocks      Used   Available Use% Mounted on
      /dev/vzfs        10485760   7836644     2649116  75% /
      /devices                0         0           0   0% /devices
      $
      

      每一列的含义如下:

      说明

      Filesystem

      代表文件系统对应的设备文件的路径名(一般是硬盘上的分区)。

      kbytes

      分区包含的数据块(1024字节)的数目。

      used

      已用空间。

      avail

      可用空间。

      capacity

      已用空间的百分比。

      Mounted on

      文件系统挂载点。


      某些目录(例如 /devices)的 kbytes、used、avail 列为0,use列为0%,这些都是特殊(或虚拟)文件系统,即使位于根目录下,也不占用硬盘空间。

      你可以结合 -h (human readable) 选项将输出信息格式化,让人更易阅读。 

      du 命令

      du (disk usage) 命令可以用来查看特定目录的空间使用情况。

      du 命令会显示每个目录所占用数据块。根据系统的不同,一个数据块可能是 512 字节或 1024 字节。举例如下:

      $du /etc
      10     /etc/cron.d
      126    /etc/default
      6      /etc/dfs
      ...
      $
      

      结合 -h 选项可以让信息显示的更加清晰:

      $du -h /etc
      5k    /etc/cron.d
      63k   /etc/default
      3k    /etc/dfs
      ...
      $
      

      挂载文件系统

      挂载是指将一个硬件设备(例如硬盘、U盘、光盘等)对应到一个已存在的目录上。 若要访问设备中的文件,必须将文件挂载到一个已存在的目录上, 然后通过访问这个目录来访问存储设备。

      这样就为用户提供了统一的接口,屏蔽了硬件设备的细节。Linux将所有的硬件设备看做文件,对硬件设备的操作等同于对文件的操作。

      注意:挂载目录可以不为空,但挂载后这个目录下以前的内容将不可用。

      需要知道的是,光盘、软盘、其他操作系统使用的文件系统的格式与linux使用的文件系统格式是不一样的,挂载需要确认Linux是否支持所要挂载的文件系统格式。

      查看当前系统所挂载的硬件设备可以使用 mount 命令:

      $ mount
      /dev/vzfs on / type reiserfs (rw,usrquota,grpquota)
      proc on /proc type proc (rw,nodiratime)
      devpts on /dev/pts type devpts (rw)
      $
      

      一般约定,/mnt 为临时挂载目录,例如挂载CD-ROM、远程网络设备、软盘等。

      也可以通过mount命令来挂载文件系统,语法为:

      mount -t file_system_type device_to_mount directory_to_mount_to
      

      例如:

      $ mount -t iso9660 /dev/cdrom /mnt/cdrom
      

      将 CD-ROM 挂载到 /mnt/cdrom 目录。

      注意:file_system_type用来指定文件系统类型,通常可以不指定,Linux会自动正确选择文件系统类型。

      挂载文件系统后,就可以通过 cd、cat 等命令来操作对应文件。

      可以通过 umount 命令来卸载文件系统。例如,卸载 cdrom:

      $ umount /dev/cdrom
      

      不过,大部分现代的Linux系统都有自动挂载卸载功能,unmount 命令较少用到。

      用户和群组配额

      用户和群组配额可以让管理员为每个用户或群组分配固定的磁盘空间。

      管理员有两种方式来分配磁盘空间:

    • 软限制:如果用户超过指定的空间,会有一个宽限期,等待用户释放空间。
    • 硬限制:没有宽限期,超出指定空间立即禁止操作。


      下面的命令可以用来管理配额:

      命令

      说明

      quota

      显示磁盘使用情况以及每个用户组的配额。

      edquota

      编辑用户和群组的配额。

      quotacheck

      查看文件系统的磁盘使用情况,创建、检查并修复配额文件。

      setquota

      设置配额。

      quotaon

      开启用户或群组的配额功能。

      quotaoff

      关闭用户或群组的配额功能。

      repquota

      打印指定文件系统的配额。

       

      Linux文件存储结构,包括目录项、inode、数据块

      大部分的Linux文件系统(如ext2、ext3)规定,一个文件由目录项、inode和数据块组成:

    • 目录项:包括文件名和inode节点号。
    • Inode:又称文件索引节点,包含文件的基础信息以及数据块的指针。
    • 数据块:包含文件的具体内容。

      先说inode

      理解inode,要从文件储存说起。文件储存在硬盘上,硬盘的最小存储单位叫做"扇区"(Sector),每个扇区储存512字节(相当于0.5KB)。

      操作系统读取硬盘的时候,不会一个扇区一个扇区地读取,这样效率太低,而是一次性连续读取多个扇区,即一次性读取一个"块"(block)。这种由多个扇区组成的"块",是文件存取的最小单位。"块"的大小,最常见的是4KB,即连续八个 sector组成一个 block。

      文件数据都储存在"块"中,那么很显然,我们还必须找到一个地方储存文件的元信息,比如文件的创建者、文件的创建日期、文件的大小等等。这种储存文件元信息的区域就叫做inode,中文译名为"索引节点"。

      inode包含文件的元信息,具体来说有以下内容:

    • 文件的字节数。
    • 文件拥有者的User ID。
    • 文件的Group ID。
    • 文件的读、写、执行权限。
    • 文件的时间戳,共有三个:ctime指inode上一次变动的时间,mtime指文件内容上一次变动的时间,atime指文件上一次打开的时间。
    • 链接数,即有多少文件名指向这个inode。
    • 文件数据block的位置。


      可以用stat命令,查看某个文件的inode信息:

      stat demo.txt
      

      总之,除了文件名以外的所有文件信息,都存在inode之中。至于为什么没有文件名,下文会有详细解释。

      当查看某个文件时,会先从inode表中查出文件属性及数据存放点,再从数据块中读取数据。

      请看文件存储结构示意图:

      inode的大小

      inode也会消耗硬盘空间,所以硬盘格式化的时候,操作系统自动将硬盘分成两个区域。一个是数据区,存放文件数据;另一个是inode区(inode table),存放inode所包含的信息。

      每个inode节点的大小,一般是128字节或256字节。inode节点的总数,在格式化时就给定,一般是每1KB或每2KB就设置一个inode。假定在一块1GB的硬盘中,每个inode节点的大小为128字节,每1KB就设置一个inode,那么inode table的大小就会达到128MB,占整块硬盘的12.8%。

      查看每个硬盘分区的inode总数和已经使用的数量,可以使用df -i 命令。

      查看每个inode节点的大小,可以用如下命令:

      sudo dumpe2fs -h /dev/hda | grep "Inode size"
      

      由于每个文件都必须有一个inode,因此有可能发生inode已经用光,但是硬盘还未存满的情况。这时,就无法在硬盘上创建新文件。

      inode号码

      每个inode都有一个号码,操作系统用inode号码来识别不同的文件。

      这里值得重复一遍,Linux系统内部不使用文件名,而使用inode号码来识别文件。对于系统来说,文件名只是inode号码便于识别的别称或者绰号。表面上,用户通过文件名,打开文件。实际上,系统内部这个过程分成三步:首先,系统找到这个文件名对应的inode号码;其次,通过inode号码,获取inode信息;最后,根据inode信息,找到文件数据所在的block,读出数据。

      使用ls -i命令,可以看到文件名对应的inode号码,例如:

      ls -i demo.txt
      

      目录项

      Linux系统中,目录(directory)也是一种文件。打开目录,实际上就是打开目录文件。

      目录文件的结构非常简单,就是一系列目录项(dirent)的列表。每个目录项,由两部分组成:所包含文件的文件名,以及该文件名对应的inode号码。

      ls命令只列出目录文件中的所有文件名:

      ls /etc
      

      ls -i命令列出整个目录文件,即文件名和inode号码:

      ls -i /etc
      

      如果要查看文件的详细信息,就必须根据inode号码,访问inode节点,读取信息。ls -l命令列出文件的详细信息。

      ls -l /etc
      

      硬链接和软链接

      硬链接

      一般情况下,文件名和inode号码是"一一对应"关系,每个inode号码对应一个文件名。但是,Linux系统允许,多个文件名指向同一个inode号码。这意味着,可以用不同的文件名访问同样的内容;对文件内容进行修改,会影响到所有文件名;但是,删除一个文件名,不影响另一个文件名的访问。这种情况就被称为"硬链接"(hard link)。

      ln命令可以创建硬链接,语法为:

      ln source_file target_file
      

      运行上面这条命令以后,源文件与目标文件的inode号码相同,都指向同一个inode。inode信息中有一项叫做"链接数",记录指向该inode的文件名总数,这时就会增加1。反过来,删除一个文件名,就会使得inode节点中的"链接数"减1。当这个值减到0,表明没有文件名指向这个inode,系统就会回收这个inode号码,以及其所对应block区域。

      这里顺便说一下目录文件的"链接数"。创建目录时,默认会生成两个目录项:"."和".."。前者的inode号码就是当前目录的inode号码,等同于当前目录的"硬链接";后者的inode号码就是当前目录的父目录的inode号码,等同于父目录的"硬链接"。所以,任何一个目录的"硬链接"总数,总是等于2加上它的子目录总数(含隐藏目录),这里的2是父目录对其的"硬链接"和当前目录下的".硬链接"。

      软链接

      除了硬链接以外,还有一种特殊情况。文件A和文件B的inode号码虽然不一样,但是文件A的内容是文件B的路径。读取文件A时,系统会自动将访问者导向文件B。因此,无论打开哪一个文件,最终读取的都是文件B。这时,文件A就称为文件B的"软链接"(soft link)或者"符号链接(symbolic link)。

      这意味着,文件A依赖于文件B而存在,如果删除了文件B,打开文件A就会报错:"No such file or directory"。这是软链接与硬链接最大的不同:文件A指向文件B的文件名,而不是文件B的inode号码,文件B的inode"链接数"不会因此发生变化。

      ln -s命令可以创建软链接,语法为:

      ln source_file target_file
      

      Linux用户管理

      在Linux中,有三种用户:

    • Root 用户:也称为超级用户,对系统拥有完全的控制权限。超级用户可以不受限制的运行任何命令。Root 用户可以看做是系统管理员。
    • 系统用户:系统用户是Linux运行某些程序所必须的用户,例如 mail 用户、sshd 用户等。系统用户通常为系统功能所必须的,不建议修改这些用户。
    • 普通用户:一般用户都是普通用户,这些用户对系统文件的访问受限,不能执行全部Linux命令。


      Linux支持用户组,用户组就是具有相同特征的用户的集合。一个组可以包含多个用户,每个用户也可以属于不同的组。用户组在Linux中扮演着重要的角色,方便管理员对用户进行集中管理。

      与用户和组有关的系统文件

      与用户和组有关的系统文件:

      系统文件

      说明

      /etc/passwd

      保存用户名和密码等信息,Linux系统中的每个用户都在/etc/passwd文件中有一个对应的记录行。这个文件对所有用户都是可读的。

      /etc/shadow

      /etc/shadow中的记录行和/etc/passwd中的相对应,他由pwconv命令根据/etc/passwd中的数据自动产生,它的格式和/etc/passwd类似,只是对密码进行了加密。并不是所有的系统都支持这个文件。

      /etc/group

      以记录行的形式保存了用户组的所有信息。


      来看一下/etc/passwd文件的结构:

      $cat /etc/passwd
      root:x:0:0:Superuser:/:
      daemon:x:1:1:System daemons:/etc:
      bin:x:2:2:Owner of system commands:/bin:
      sys:x:3:3:Owner of system files:/usr/sys:
      adm:x:4:4:System accounting:/usr/adm:
      uucp:x:5:5:UUCP administrator:/usr/lib/uucp:
      auth:x:7:21:Authentication administrator:/tcb/files/auth:
      cron:x:9:16:Cron daemon:/usr/spool/cron:
      listen:x:37:4:Network daemon:/usr/net/nls:
      lp:x:71:18:printer administrator:/usr/spool/lp:
      sam:x:200:50:Sam san:/usr/sam:/bin/sh
      

      可以看到,/etc/passwd文件中一行记录对应着一个用户,每行记录又被冒号分隔为7个字段,其格式和具体含义如下图所示:


      对每个字段的说明:

      字段

      说明

      用户名

      用户名是惟一的,长度根据不同的linux系统而定,一般是8位。

      密码

      由于系统中还有一个/etc/shadow文件用于存放加密后的口令,所以在这里这一项是"x"来表示,如果用户没有设置口令,则该项为空。如果passwd字段中的第一个字符是"*"的话,那么,就表示该账号被查封了,系统不允许持有该账号的用户登录。

      用户ID

      系统内部根据用户ID而不是用户名来识别不同的用户,用户ID有以下几种:

    • 0代表系统管理员,如果你想建立一个系统管理员的话,可以建立一个普通帐户,然后将该账户的用户ID改为0即可。
    • 1~500系统预留的ID。
    • 500以上是普通用户使用。
    • 组ID

      其实这个和用户ID差不多,用来管理群组,与/etc/group文件相关。

      描述信息

      这个字段几乎没有什么用,只是用来解释这个账号的意义。在不同的Linux系统中,这个字段的 格式并没有统一。在许多Linux系统中,这个字段存放的是一段任意的注释性描述文字,用做finger命令的输出。

      用户主目录

      用户登录系统的起始目录。用户登录系统后将首先进入该目录。root用户默认是/,普通用户是/home/username。

      用户Shell

      用户登录系统时使用的Shell。

      管理用户和组

      下面是一些常用的管理用户和组的命令:

      命令

      说明

      useradd

      添加用户。

      usermod

      修改用户信息。

      userdel

      删除用户。

      groupadd

      添加用户组。

      groupmod

      修改用户组信息。

      groupdel

      删除用户组。

      创建用户组

      添加用户时,可以将用户添加到现有的用户组,或者创建一个新的用户组。可以在 /etc/groups 文件中看到所有的用户组信息。

      默认的用户组通常用来管理系统用户,不建议将普通用户添加到这些用户组。使用groupadd命令创建用户组的语法为:

      groupadd [-g gid [-o]] [-r] [-f] groupname
      

      每个选项的含义如下:

      选项

      说明

      -g GID

      以数字表示的用户组ID。

      -o

      可以使用重复的组ID。

      -r

      建立系统组,用来管理系统用户。

      -f

      强制创建。

      groupname

      用户组的名称。


      如果不指定选项,系统将使用默认值。例如创建一个 developers 用户组:

      $ groupadd developers
      

      修改用户组

      groupmod命令可以用来修改用户组,语法为:

      $ groupmod -n new_modified_group_name old_group_name
      

      例如,将用户组 developers_2 重命名为 developer:

      $ groupmod -n developer developer_2
      

      将developer用户组的ID改为545:

      $ groupmod -g 545 developer
      

      删除用户组

      通过groupdel命令可以删除用户组。例如,删除developer组:

      $ groupdel developer
      

      groupdel 仅仅删除用户组,并不删除与之相关的文件,这些文件仍然可以被所有者访问。

      添加用户

      添加用户可以使用useradd命令,语法为:

      useradd -d homedir -g groupname -m -s shell -u userid accountname
      

      每个选项的含义如下:

      选项

      描述

      -d homedir

      指定用户主目录。

      -g groupname

      指定用户组。

      -m

      如果主目录不存在,就创建。

      -s shell

      为用户指定默认Shell。

      -u userid

      指定用户ID。

      accountname

      用户名。


      如果不指定任何选项,系统将使用默认值。useradd 命令将会修改 /etc/passwd、/etc/shadow、and /etc/group 三个文件,并创建用户主目录。

      下面的例子将会添加用户 mcmohd,并设置主目录为 /home/mcmohd,用户组为 developers,默认 Shell 为  Korn Shell:

      $ useradd -d /home/mcmohd -g developers -s /bin/ksh mcmohd
      

      注意:添加用户前请确认 developers 用户组存在。

      用户被创建后,可以使用 passwd 命令来设置密码,例如:

      $ passwd mcmohd20
      Changing password for user mcmohd20.
      New Linux password:******
      Retype new UNIX password:******
      passwd: all authentication tokens updated successfully.
      

      注意:如果你是管理员,输入 $ passwd username 可以修改你所管理的用户的密码;否则只能修改你自己的密码(不需要提供username)。

      修改用户

      usermod 命令可以修改现有用户的信息。usermod 命令的选项和 useradd 相同,不过可以增加 -l 选项来更改用户名。

      下面的例子将用户 mcmohd 的用户名修改为 mcmohd20,主目录修改为 /home/mcmohd20:

      $ usermod -d /home/mcmohd20 -m -l mcmohd mcmohd20
      

      删除用户

      userdel 命令可以用来删除现有用户。userdel 是一个危险的命令,请谨慎使用。

      userdel 命令仅有一个选项 -r,用来删除用户主目录和本地邮件。例如,删除用户  mcmohd20:

      $ userdel -r mcmohd20
      

      为了便于恢复被误删的用户,可以忽略 -r 选项,保留用户主目录,之后确认无误可以随时删除主目录。

      Linux系统性能分析

      这篇教程的目的是向大家介绍一些免费的系统性能分析工具(命令),使用这些工具可以监控系统资源使用情况,便于发现性能瓶颈。

      系统的整体性能取决于各种资源的平衡,类似木桶理论,某种资源的耗尽会严重阻碍系统的性能。


      Linux中需要监控的资源主要有 CPU、主存(内存)、硬盘空间、I/O时间、网络时间、应用程序等。

      影响系统性能的主要因素有:

      因素

      说明

      用户态CPU

      CPU在用户态运行用户程序所花费的时间,包括库调用,但是不包括内核花费的时间。

      内核态CPU

      CPU在内核态运行系统服务所花费的时间。所有的 I/O 操作都需要调用系统服务,程序员可以通过阻塞 I/O 传输来影响这部分的时间。

      I/O 时间和网络时间

      响应 I/O 请求、处理网络连接所花费的时间。

      内存

      切换上下文和交换数据(虚拟内存页导入和导出)花费的时间。

      应用程序

      程序等待运行的时间——CPU正在运行其他程序,等待切换到当前程序。


      说明:一般认为用户态CPU和内核态CPU花费的时间小于70%时是良好状态。

      下面的命令可以用来监控系统性能并作出相应调整:

      命令

      说明

      nice

      启动程序时指定进程优先级。

      renice

      调整现有进程的优先级。

      netstat

      显示各种网络相关信息,包括网络连接情况、路由表、接口状态(Interface Statistics)、masquerade 连接、多播成员 (Multicast Memberships)等。实际上,netstat 用于显示与IP、TCP、UDP和ICMP协议相关的统计数据,一般用于检验本机各端口的网络连接情况。

      time

      检测一个命令运行时间以及资源(CPU、内存、I/O等)使用情况。

      uptime

      查看系统负载情况。

      ps

      查看系统中进程的资源使用情况(瞬时状态,不是动态监控)。

      vmstat

      报告虚拟内存使用情况。

      gprof

      精确分析程序的性能,能给出函数调用时间、调用次数、调用关系等。

      top

      实时监控系统中各个进程资源的资源使用情况。


      常用命令组合:

    • vmstat、sar、mpstat检测是否存在CPU瓶颈;
    • vmstat、free检测是否存在内存瓶颈;
    • iostat检测是否存在磁盘I/O瓶颈;
    • netstat检测是否存在网络I/O瓶颈。

      Linux系统日志及日志分析

      Linux系统拥有非常灵活和强大的日志功能,可以保存几乎所有的操作记录,并可以从中检索出我们需要的信息。

      大部分Linux发行版默认的日志守护进程为 syslog,位于 /etc/syslog 或 /etc/syslogd,默认配置文件为 /etc/syslog.conf,任何希望生成日志的程序都可以向 syslog 发送信息。 

      Linux系统内核和许多程序会产生各种错误信息、警告信息和其他的提示信息,这些信息对管理员了解系统的运行状态是非常有用的,所以应该把它们写到日志文件中去。完成这个过程的程序就是syslog。syslog可以根据日志的类别和优先级将日志保存到不同的文件中。例如,为了方便查阅,可以把内核信息与其他信息分开,单独保存到一个独立的日志文件中。默认配置下,日志文件通常都保存在"/var/log"目录下。

      日志类型

      下面是常见的日志类型,但并不是所有的Linux发行版都包含这些类型:

      类型

      说明

      auth

      用户认证时产生的日志,如login命令、su命令。

      authpriv

      与 auth 类似,但是只能被特定用户查看。

      console

      针对系统控制台的消息。

      cron

      系统定期执行计划任务时产生的日志。

      daemon

      某些守护进程产生的日志。

      ftp

      FTP服务。

      kern

      系统内核消息。

      local0.local7

      由自定义程序使用。

      lpr

      与打印机活动有关。

      mail

      邮件日志。

      mark

      产生时间戳。系统每隔一段时间向日志文件中输出当前时间,每行的格式类似于 May 26 11:17:09 rs2 -- MARK --,可以由此推断系统发生故障的大概时间。

      news

      网络新闻传输协议(nntp)产生的消息。

      ntp

      网络时间协议(ntp)产生的消息。

      user

      用户进程。

      uucp

      UUCP子系统。

      日志优先级

      常见的日志优先级请见下标:

      优先级

      说明

      emerg

      紧急情况,系统不可用(例如系统崩溃),一般会通知所有用户。

      alert

      需要立即修复,例如系统数据库损坏。

      crit

      危险情况,例如硬盘错误,可能会阻碍程序的部分功能。

      err

      一般错误消息。

      warning

      警告。

      notice

      不是错误,但是可能需要处理。

      info

      通用性消息,一般用来提供有用信息。

      debug

      调试程序产生的信息。

      none

      没有优先级,不记录任何日志消息。

      常见日志文件

      所有的系统应用都会在 /var/log 目录下创建日志文件,或创建子目录再创建日志文件。例如:

      文件/目录

      说明

      /var/log/boot.log

      开启或重启日志。

      /var/log/cron

      计划任务日志

      /var/log/maillog

      邮件日志。

      /var/log/messages

      该日志文件是许多进程日志文件的汇总,从该文件可以看出任何入侵企图或成功的入侵。

      /var/log/httpd 目录

      Apache HTTP 服务日志。

      /var/log/samba 目录

      samba 软件日志

       

      /etc/syslog.conf 文件

      /etc/syslog.conf 是 syslog 的配置文件,会根据日志类型和优先级来决定将日志保存到何处。典型的 syslog.conf 文件格式如下所示:

      *.err;kern.debug;auth.notice /dev/console
      daemon,auth.notice           /var/log/messages
      lpr.info                     /var/log/lpr.log
      mail.*                       /var/log/mail.log
      ftp.*                        /var/log/ftp.log
      auth.*                       @see.xidian.edu.cn
      auth.*                       root,amrood
      netinfo.err                  /var/log/netinfo.log
      install.*                    /var/log/install.log
      *.emerg                      *
      *.alert                      |program_name
      mark.*                       /dev/console
      

      第一列为日志类型和日志优先级的组合,每个类型和优先级的组合称为一个选择器;后面一列为保存日志的文件、服务器,或输出日志的终端。syslog 进程根据选择器决定如何操作日志。

      对配置文件的几点说明:

    • 日志类型和优先级由点号(.)分开,例如 kern.debug 表示由内核产生的调试信息。
    • kern.debug 的优先级大于 debug。
    • 星号(*)表示所有,例如 *.debug 表示所有类型的调试信息,kern.* 表示由内核产生的所有消息。
    • 可以使用逗号(,)分隔多个日志类型,使用分号(;)分隔多个选择器。


      对日志的操作包括:

    • 将日志输出到文件,例如 /var/log/maillog 或 /dev/console。
    • 将消息发送给用户,多个用户用逗号(,)分隔,例如 root, amrood。
    • 通过管道将消息发送给用户程序,注意程序要放在管道符(|)后面。
    • 将消息发送给其他主机上的 syslog 进程,这时 /etc/syslog.conf 文件后面一列为以@开头的主机名,例如@see.xidian.edu.cn。

      logger 命令

      logger 是Shell命令,可以通过该命令使用 syslog 的系统日志模块,还可以从命令行直接向系统日志文件写入一行信息。

      logger命令的语法为:

      logger [-i] [-f filename] [-p priority] [-t tag] [message...]
      

      每个选项的含义如下:

      选项

      说明

      -f filename

      将 filename 文件的内容作为日志。

      -i

      每行都记录 logger 进程的ID。

      -p priority

      指定优先级;优先级必须是形如 facility.priority 的完整的选择器,默认优先级为 user.notice。

      -t tag

      使用指定的标签标记每一个记录行。

      message

      要写入的日志内容,多条日志以空格为分隔;如果没有指定日志内容,并且 -f filename 选项为空,那么会把标准输入作为日志内容。


      例如,将ping命令的结果写入日志:

      $ ping 192.168.0.1 | logger -it logger_test -p local3.notice&
      $ tail -f /var/log/userlog
      Oct 6 12:48:43 kevein logger_test[22484]: PING 192.168.0.1 (192.168.0.1) 56(84) bytes of data.
      Oct 6 12:48:43 kevein logger_test[22484]: 64 bytes from 192.168.0.1: icmp_seq=1 ttl=253 time=49.7 ms
      Oct 6 12:48:44 kevein logger_test[22484]: 64 bytes from 192.168.0.1: icmp_seq=2 ttl=253 time=68.4 ms
      Oct 6 12:48:45 kevein logger_test[22484]: 64 bytes from 192.168.0.1: icmp_seq=3 ttl=253 time=315 ms
      Oct 6 12:48:46 kevein logger_test[22484]: 64 bytes from 192.168.0.1: icmp_seq=4 ttl=253 time=279 ms
      Oct 6 12:48:47 kevein logger_test[22484]: 64 bytes from 192.168.0.1: icmp_seq=5 ttl=253 time=347 ms
      Oct 6 12:48:49 kevein logger_test[22484]: 64 bytes from 192.168.0.1: icmp_seq=6 ttl=253 time=701 ms
      Oct 6 12:48:50 kevein logger_test[22484]: 64 bytes from 192.168.0.1: icmp_seq=7 ttl=253 time=591 ms
      Oct 6 12:48:51 kevein logger_test[22484]: 64 bytes from 192.168.0.1: icmp_seq=8 ttl=253 time=592 ms
      Oct 6 12:48:52 kevein logger_test[22484]: 64 bytes from 192.168.0.1: icmp_seq=9 ttl=253 time=611 ms
      Oct 6 12:48:53 kevein logger_test[22484]: 64 bytes from 192.168.0.1: icmp_seq=10 ttl=253 time=931 ms
      

      ping命令的结果成功输出到 /var/log/userlog 文件。

      命令 logger -it logger_test -p local3.notice 各选项的含义:

    • -i:在每行都记录进程ID;
    • -t logger_test:每行记录都加上"logger_test"这个标签;
    • -p local3.notice:设置日志类型和优先级。

      日志转储

      日志转储也叫日志回卷或日志轮转。Linux中的日志通常增长很快,会占用大量硬盘空间,需要在日志文件达到指定大小时分开存储。

      syslog 只负责接收日志并保存到相应的文件,但不会对日志文件进行管理,因此经常会造成日志文件过大,尤其是WEB服务器,轻易就能超过1G,给检索带来困难。

      大多数Linux发行版使用 logrotate 或 newsyslog 对日志进行管理。logrotate 程序不但可以压缩日志文件,减少存储空间,还可以将日志发送到指定 E-mail,方便管理员及时查看日志。

      例如,规定邮件日志 /var/log/maillog 超过1G时转储,每周一次,那么每隔一周 logrotate 进程就会检查 /var/log/maillog 文件的大小:

    • 如果没有超过1G,不进行任何操作。
    • 如果在1G~2G之间,就会创建新文件 /var/log/maillog.1,并将多出的1G日志转移到该文件,以给 /var/log/maillog 文件瘦身。
    • 如果在2G~3G之间,会继续创建新文件 /var/log/maillog.2,并将 /var/log/maillog.1 的内容转移到该文件,将 /var/log/maillog 的内容转移到 /var/log/maillog.1,以保持 /var/log/maillog 文件不超过1G。


      可以看到,每次转存都会创建一个新文件(如果不存在),命名格式为日志文件名加一个数字(从1开始自动增长),以保持当前日志文件和转存后的日志文件不超过指定大小。

      logrotate 的主要配置文件是 /etc/logrotate.conf,/etc/logrotate.d 目录是对 /etc/logrotate.conf 的补充,或者说为了不使 /etc/logrotate.conf 过大而设置。

      可以通过 cat 命令查看它的内容:

      $cat /etc/logrotate.conf
      # see "man logrotate" for details  //可以查看帮助文档
      # rotate log files weekly
      weekly                             //设置每周转储一次
      # keep 4 weeks worth of backlogs
      rotate 4                           //最多转储4次
      # create new (empty) log files after rotating old ones
      create                             //当转储后文件不存储时创建它
      # uncomment this if you want your log files compressed
      #compress                          //以压缩方式转储
      # RPM packages drop log rotation information into this directory
      include /etc/logrotate.d           //其他日志文件的转储方式,包含在该目录下
      # no packages own wtmp -- we'll rotate them here
      /var/log/wtmp {                    //设置/var/log/wtmp日志文件的转储参数
          monthly                        //每月转储
          create 0664 root utmp          //转储后文件不存在时创建它,文件所有者为root,所属组为utmp,对应的权限为0664
          rotate 1                       //最多转储一次
      }
      


      注意:include 允许管理员把多个分散的文件集中到一个,类似于C语言的 #include,将其他文件的内容包含进当前文件。

      include 非常有用,一些程序会把转储日志的配置文件放在 /etc/logrotate.d 目录,这些配置文件会覆盖或增加 /etc/logrotate.conf 的配置项,如果没有指定相关配置,那么采用 /etc/logrotate.conf 的默认配置。

      所以,建议将 /etc/logrotate.conf 作为默认配置文件,第三方程序在 /etc/logrotate.d 目录下自定义配置文件。

      logrotate 也可以作为命令直接运行来修改配置文件。

      Linux信号机制与信号处理

      信号(signal)是Linux进程间通信的一种机制,全称为软中断信号,也被称为软中断。信号本质上是在软件层次上对硬件中断机制的一种模拟。

      与其他进程间通信方式(例如管道、共享内存等)相比,信号所能传递的信息比较粗糙,只是一个整数。但正是由于传递的信息量少,信号也便于管理和使用,可以用于系统管理相关的任务,例如通知进程终结、中止或者恢复等。

      每种信号用一个整型常量宏表示,以SIG开头,比如SIGCHLD、SIGINT等,它们在系统头文件<signal.h>中定义。

      信号由内核(kernel)管理,产生方式多种多样:

    • 可以由内核自身产生,比如出现硬件错误、内存读取错误,分母为0的除法等,内核需要通知相应进程。
    • 也可以由其他进程产生并发送给内核,再由内核传递给目标进程。


      信号传递的过程:

    • 内核中针对每一个进程都有一个表来保存信号。
    • 当内核需要将信号传递给某个进程时,就在该进程对应的表中写入信号,这样就生成了信号。
    • 当该进程由用户态陷入内核态,再次切换到用户态之前,会查看表中的信号。如果有信号,进程就会首先执行信号对应的操作,此时叫做执行信号。
    • 从生成信号到将信号传递给对应进程这段时间,信号处于等待状态。
    • 我们可以编写代码,让进程阻塞(block)某些信号,也就是让这些信号始终处于等待的状态,直到进程取消阻塞(unblock)或者忽略信号。

      信号种类

      下表列出了一些常见信号:

      信号名称

      数字表示

      说明

      SIGHUP

      1

      终端挂起或控制进程终止。当用户退出Shell时,由该进程启动的所有进程都会收到这个信号,默认动作为终止进程。

      SIGINT

      2

      键盘中断。当用户按下<Ctrl+C>组合键时,用户终端向正在运行中的由该终端启动的程序发出此信号。默认动作为终止进程。 

      SIGQUIT

      3

      键盘退出键被按下。当用户按下<Ctrl+D>或<Ctrl+\>组合键时,用户终端向正在运行中的由该终端启动的程序发出此信号。默认动作为退出程序。

      SIGFPE

      8

      发生致命的运算错误时发出。不仅包括浮点运算错误,还包括溢出及除数为0等所有的算法错误。默认动作为终止进程并产生core文件。

      SIGKILL

      9

      无条件终止进程。进程接收到该信号会立即终止,不进行清理和暂存工作。该信号不能被忽略、处理和阻塞,它向系统管理员提供了可以杀死任何进程的方法。

      SIGALRM

      14

      定时器超时,默认动作为终止进程。

      SIGTERM

      15

      程序结束信号,可以由 kill 命令产生。与SIGKILL不同的是,SIGTERM 信号可以被阻塞和终止,以便程序在退出前可以保存工作或清理临时文件等。


      通过 kill -l 命令可以查看系统支持的所有信号:

      $ kill -l
      1) SIGHUP       2) SIGINT       3) SIGQUIT      4) SIGILL
      5) SIGTRAP      6) SIGABRT      7) SIGBUS       8) SIGFPE
      9) SIGKILL     10) SIGUSR1     11) SIGSEGV     12) SIGUSR2
      13) SIGPIPE     14) SIGALRM     15) SIGTERM     16) SIGSTKFLT
      17) SIGCHLD     18) SIGCONT     19) SIGSTOP     20) SIGTSTP
      21) SIGTTIN     22) SIGTTOU     23) SIGURG      24) SIGXCPU
      25) SIGXFSZ     26) SIGVTALRM   27) SIGPROF     28) SIGWINCH
      29) SIGIO       30) SIGPWR      31) SIGSYS      34) SIGRTMIN
      35) SIGRTMIN+1  36) SIGRTMIN+2  37) SIGRTMIN+3  38) SIGRTMIN+4
      39) SIGRTMIN+5  40) SIGRTMIN+6  41) SIGRTMIN+7  42) SIGRTMIN+8
      43) SIGRTMIN+9  44) SIGRTMIN+10 45) SIGRTMIN+11 46) SIGRTMIN+12
      47) SIGRTMIN+13 48) SIGRTMIN+14 49) SIGRTMIN+15 50) SIGRTMAX-14
      51) SIGRTMAX-13 52) SIGRTMAX-12 53) SIGRTMAX-11 54) SIGRTMAX-10
      55) SIGRTMAX-9  56) SIGRTMAX-8  57) SIGRTMAX-7  58) SIGRTMAX-6
      59) SIGRTMAX-5  60) SIGRTMAX-4  61) SIGRTMAX-3  62) SIGRTMAX-2
      63) SIGRTMAX-1  64) SIGRTMAX
      

      上面仅是一个演示,不同的Linux发行版支持的信号可能不同。

      每种信号都会有一个默认动作。默认动作就是脚本或程序接收到该信号所做出的默认操作。常见的默认动作有终止进程、退出程序、忽略信号、重启暂停的进程等,上表中也对部分默认动作进行了说明。

      发送信号

      有多种方式可以向程序或脚本发送信号,例如按下<Ctrl+C>组合键会发送SIGINT信号,终止当前进程。

      还可以通过 kill 命令发送信号,语法为:

      $ kill -signal pid
      

      signal为要发送的信号,可以是信号名称或数字;pid为接收信号的进程ID。例如:

      $ kill -1 1001
      

      将SIGHUP信号发送给进程ID为1001的程序,程序会终止执行。

      又如,强制杀死ID为1001的进程:

      $ kill -9 1001
      

      捕获信号

      通常情况下,直接终止进程并不是我们所希望的。例如,按下<Ctrl+C>,进程被立即终止,不会清理创建的临时文件,带来系统垃圾,也不会保存正在进行的工作,导致需要重做。

      可以通过编程来捕获这些信号,当终止信号出现时,可以先进行清场和保存处理,再退出程序。

      用户程序可以通过C/C++等代码捕获信号,这将在Linux C编程中进行讲解,这里仅介绍如果通过Linux命令捕获信号。

      通过 trap 命令就可以捕获信号,语法为:

      $ trap commands signals
      

      commands为Linux系统命令或用户自定义命令;signals为要捕获的信号,可以为信号名称或数字。

      捕获到信号后,可以有三种处理:

    • 执行一段脚本来做一些处理工作,例如清理临时文件;
    • 接受(恢复)信号的默认操作;
    • 忽略当前信号。

      1) 清理临时文件

      脚本捕获到终止信号后一个常见的动作就是清理临时文件。例如:

      $ trap "rm -f $WORKDIR/work1$$ $WORKDIR/dataout$$; exit" 2
      

      当用户按下<Ctrl+C>后,脚本先清理临时文件 work1$$ 和 dataout$$ 再退出。

      注意:exit 命令是必须的,否则脚本捕获到信号后会继续执行而不是退出。

      修改上面的脚本,使接收到 SIGHUP 时进行同样的操作:

      $ trap "rm $WORKDIR/work1$$ $WORKDIR/dataout$$; exit" 1 2
      

      几点注意:

    • 如果执行多个命令,需要将命令用引号包围;
    • 只有脚本执行到 trap 命令时才会捕获信号;
    • 再次接收到信号时还会执行同样的操作。


      上面的脚本,执行到 trap 命令时就会替换 WORKDIR 和 $$ 的值。如果希望接收到 SIGHUP 或 SIGINT 信号时再替换其值,那么可以将命令放在单引号内,例如:

      $ trap 'rm $WORKDIR/work1$$ $WORKDIR/dataout$$; exit' 1 2
      

      2) 忽略信号

      如果 trap 命令的 commands 为空,将会忽略接收到的信号,即不做任何处理,也不执行默认动作。例如:

      $ trap '' 2
      

      也可以同时忽略多个信号:

      $ trap '' 1 2 3 15
      

      注意:必须被引号包围,不能写成下面的形式:

      $ trap  2
      

      3) 恢复默认动作

      如果希望改变信号的默认动作后再次恢复默认动作,那么省略 trap 命令的 commands 即可,例如:

      $ trap 1 2
      

      将恢复SIGHUP 和 SIGINT 信号的默认动作。

       

    展开全文
  • 第五章——Linux基础

    2020-05-28 09:33:27
    Linux初体验 Linux进阶
  • linux的入门介绍

    2019-06-13 15:00:58
    1. linux是一个开源、免费的操作系统,其稳定性、安全性、处理多并发已经得到 业界的认可,目前很多企业级的项目都会部署到Linux/unix系统上。 2. 常见的操作系统(win7、IOS、Android、Mac) 2.linux的应用领域 ...

    1.背景介绍

    1. linux是一个开源、免费的操作系统,其稳定性、安全性、处理多并发已经得到 业界的认可,目前很多企业级的项目都会部署到Linux/unix系统上。

    2. 常见的操作系统(win7、IOS、Android、Mac)

    2.linux的应用领域

        2.1  个人桌面领域的应用 此领域是传统linux应用最薄弱的环节,传统linux由于界面简单、操作复杂、应用软件少的缺 点,一直被windows所压制,但近些年来随着ubuntu、fedora [fɪˈdɔ:rə] 等优秀桌面环境的兴 起,同时各大硬件厂商对其支持的加大,linux在个人桌面领域的占有率在逐渐的提高。

        2.2  服务器领域 linux在服务器领域的应用是最强的。 linux免费、稳定、高效等特点在这里得到了很好的体现,近些年来linux服务器市场得到了飞 速的提升,尤其在一些高端领域尤为广泛。
        2.3   嵌入式领域
    近些年来linux在嵌入式领域的应用得到了飞速的提高
    linux运行稳定、对网络的良好支持性、低成本,且可以根据需要进行软件裁剪,内核最小 可以达到几百KB等特点,使其近些年来在嵌入式领域的应用得到非常大的提高
    主要应用:机顶盒、数字电视、网络电话、程控交换机、手机、PDA、智能家居、智能硬件 等都是其应用领域。以后再物联网中应用会更加广泛。

    3. linux的创始人

    4.linux主要发行的版本

     .Linux主要的发行版: Ubuntu(乌班图)、RedHat(红帽)、CentOS、Debain[蝶变]、Fedora、SuSE、 OpenSUSE

    5.Linux和Unix的关系-unix是怎么来的
     

     

    linux和window比较

     

    6.环境准备

    6.1.可以直接使用云服务器(阿里云,腾讯云,AWS云等),省去各种麻烦步骤

    6.2.可以直接使用装virtual machine,


        CentOS下载地址:http://mirrors.163.com/centos/7/isos/ 

       6.2.1) 创建虚拟机
       6.2.2) 开始安装系统(CentOS7.3)

     

    7.linux的目录介绍

    linux的文件系统是采用级层式的树状目录结构,在此结构中的最上层是根目录“/”,然后在此 目录下再创建其他的目录。 深刻理解linux树状文件目录是非常重要的,这里我给大家说明一下

     

      1):/bin   [***]   (/usr/bin 、 /usr/local/bin) • 是Binary的缩写, 这个目录存放着最经常使用的命令

      2): /sbin (/usr/sbin 、 /usr/local/sbin) • s就是Super User的意思,这里存放的是系统管理员使用的系统管理程序
      3):/home [***] • 存放普通用户的主目录,在Linux中每个用户都有一个自己的目录,一般 该目录名是以用户的账号命名的。
      4):/root [***] • 该目录为系统管理员,也称作超级权限者的用户主目录。

      5): /lib • 系统开机所需要最基本的动态连接共享库,其作用类似于Windows里的DLL文件。几 乎所有的应用程序都需要用到这些共享库。
      6):/lost+found • 这个目录一般情况下是空的,当系统非法关机后,这里就存放了一些文件。
      7):/etc [***] • 所有的系统管理所需要的配置文件和子目录 my.conf 
      8):/usr  [***] • 这是一个非常重要的目录,用户的很多应用程序和文件都放在这个目录下,类似与 windows下的program files目录

      9):/boot [***] • 存放的是启动Linux时使用的一些核心文件,包括一些连接文件以及镜像文件
    10):/srv • service缩写,该目录存放一些服务启动之后需要提取的数据。

    11):/sys • 这是linux2.6内核的一个很大的变化。该目录下安装了2.6内核中新出现的一个文件系统 sysfs
     12):tmp • 这个目录是用来存放一些临时文件的

     13):/dev • 类似于windows的设备管理器,把所有的硬件用文件的形式存储。
    14):/media [***] • linux系统会自动识别一些设备,例如U盘、光驱等等,当识别后,linux 会把识别的设备挂载到这个目录下。
    15):/mnt [***] • 系统提供该目录是为了让用户临时挂载别的文件系统的,我们可以将外部的存储挂 载在/mnt/上,然后进入该目录就可以查看里的内容了。
    16):/opt     • 这是给主机额外安装软件所摆放的目录。如安装ORACLE数据库就可放到该目录下。 默认为空。

     17):/usr/local [***] • 这是另一个给主机额外安装软件所安装的目录。一般是通过编译源码方式安装的程序

    18):/var [***] • 这个目录中存放着在不断扩充着的东西,习惯将经常被修改的目录放在这个目录下。 包括各种日志文件

     

    8远程登录

     为什么需要远程登录Linux
    1) linux服务器是开发小组共享的.

    2) 正式上线的项目是运行在公网的.

    3) 因此程序员需要远程登录到centos进行项目管理或者开发.

    4) 画出简单的网络拓扑示意图(帮助理解)
    5) 远程登录客户端有 Xshell5, Xftp5 , 我们学习使用 Xshell5 和 Xftp , 其它的 远程工具大同小异.

    远程登录Linux-Xshell5
    介绍:
    说明: Xshell 是目前最好的远程登录到Linux操作的软件,流畅的速度并且完 美解决了中文乱码的问题, 是目前程序员首选的软件。
    Xshell [1] 是一个强大的安全终端模拟软件,它支持SSH1, SSH2, 以及Microsoft Windows 平台的TELNET 协议。
    Xshell可以在Windows界面下用来访问远端不同系统下的服务器,从而比较好 的达到远程控制终端的目的

    展开全文
  • Linux基础教程

    2019-06-16 11:08:09
    linux中,最最重要的就是命令,这就包含了2个过程,输入和输出 输入:输入当然就是打开终端,然后按键盘输入,然后按回车,输入格式一般就是这类的 #创建一个名为 file 的文件,touch是一个命令 $ touch file #...

     

    写在前面

    在linux中,最最重要的就是命令,这就包含了2个过程,输入和输出

    • 输入:输入当然就是打开终端,然后按键盘输入,然后按回车,输入格式一般就是这类的

    #创建一个名为 file 的文件,touch是一个命令 $ touch file #进入一个目录,cd是一个命令 $ cd /etc/ #查看当前所在目录 $ pwd

    • 输出:输出会返回你想要的结果,比如你要看什么文件,就会返回文件的内容。如果只是执行,执行失败会告诉你哪里错了,如果执行成功那么会没有输出,因为linux的哲学就是:没有结果就是最好的结果

    开始

    如图,双击桌面上的 Xfce 终端 图标打开终端后系统会自动运行 Shell 程序,然后我们就可以输入命令让系统来执行了:

    1) 重要快捷键:

    真正学习命令行之前,你先要掌握几个十分有用、必需掌握的小技巧:

    [Tab]

    使用Tab键来进行命令补全,Tab键一般是在字母Q旁边,这个技巧给你带来的最大的好处就是当你忘记某个命令的全称时可以只输入它的开头的一部分,然后按下Tab键就可以得到提示或者帮助完成:

    当然不止补全命令,补全目录、补全命令参数都是没问题的:

    [Ctrl+c]

    想想你有没有遇到过这种情况,当你在 Linux 命令行中无意输入了一个不知道的命令,或者错误地使用了一个命令,导致在终端里出现了你无法预料的情况,比如,屏幕上只有光标在闪烁却无法继续输入命令,或者不停地输出一大堆你不想要的结果。你想要立即停止并恢复到你可控的状态,那该怎么办呢?这时候你就可以使用Ctrl+c键来强行终止当前程序(你可以放心它并不会使终端退出)。

    尝试输入以下命令:

    $ tail

    然后你会发现你接下来的输入都没有任何反应了,只是将你输入的东西显示出来,现在你可以使用Ctrl+c,来中断这个你目前可能还不知道是什么的程序(在后续课程中我们会具体解释这个tail命令是什么)。

    又或者输入:

    $ find /

    显然这不是你想的结果,可以使用Ctrl+c结束。

    虽然这个按着很方便,但不要随便按,因为有时候,当你看到终端没有任何反应或提示,也不能接受你的输入时,可能只是运行的程序需要你耐心等一下,就不要急着按Ctrl+c了。

    其他一些常用快捷键

    按键

    作用

    Ctrl+d

    键盘输入结束或退出终端

    Ctrl+s

    暂停当前程序,暂停后按下任意键恢复运行

    Ctrl+z

    将当前程序放到后台运行,恢复到前台为命令fg

    Ctrl+a

    将光标移至输入行头,相当于Home键

    Ctrl+e

    将光标移至输入行末,相当于End键

    Ctrl+k

    删除从光标所在位置到行末

    Alt+Backspace

    向前删除一个单词

    Shift+PgUp

    将终端显示向上滚动

    Shift+PgDn

    将终端显示向下滚动

    2) 学会利用历史输入命令

    很简单,你可以使用键盘上的方向上键↑,恢复你之前输入过的命令,你一试便知。

    3) 学会使用通配符

    通配符是一种特殊语句,主要有星号(*)和问号(?),用来对字符串进行模糊匹配(比如文件名、参数名)。当查找文件夹时,可以使用它来代替一个或多个真正字符;当不知道真正字符或者懒得输入完整名字时,常常使用通配符代替一个或多个真正字符。

    终端里面输入的通配符是由 Shell 处理的,不是由所涉及的命令语句处理的,它只会出现在命令的“参数值”里(它不能出现在命令名称里, 命令不记得,那就用Tab补全)。当 Shell 在“参数值”中遇到了通配符时,Shell 会将其当作路径或文件名在磁盘上搜寻可能的匹配:若符合要求的匹配存在,则进行代换(路径扩展);否则就将该通配符作为一个普通字符传递给“命令”,然后再由命令进行处理。总之,通配符实际上就是一种 Shell 实现的路径扩展功能。在通配符被处理后, Shell 会先完成该命令的重组,然后继续处理重组后的命令,直至执行该命令。

    首先回到用户家目录:

    $ cd /home/shiyanlou

    然后使用 touch 命令创建 2 个文件,后缀都为 txt:

    $ touch asd.txt fgh.txt

    可以给文件随意命名,假如过了很长时间,你已经忘了这两个文件的文件名,现在你想在一大堆文件中找到这两个文件,就可以使用通配符:

    $ ls *.txt

    在创建文件的时候,如果需要一次性创建多个文件,比如:“love_1_linux.txt,love_2_linux.txt,... love_10_linux.txt”。在 Linux 中十分方便:

    $ touch love_{1..10}_shiyanlou.txt

    Shell 常用通配符:

    字符

    含义

    *

    匹配 0 或多个字符

    ?

    匹配任意一个字符

    [list]

    匹配 list 中的任意单一字符

    [^list]

    匹配 除list 中的任意单一字符以外的字符

    [c1-c2]

    匹配 c1-c2 中的任意单一字符 如:[0-9] [a-z]

    {string1,string2,...}

    匹配 string1 或 string2 (或更多)其一字符串

    {c1..c2}

    匹配 c1-c2 中全部字符 如{1..10}

    4) 学会在命令行中获取帮助

    在 Linux 环境中,如果你遇到困难,可以使用man命令,它是Manual pages的缩写。

    Manual pages 是 UNIX 或类 UNIX 操作系统中在线软件文档的一种普遍的形式, 内容包括计算机程序(包括库和系统调用)、正式的标准和惯例,甚至是抽象的概念。用户可以通过执行man命令调用手册页。

    你可以使用如下方式来获得某个命令的说明和使用方式的详细介绍:

    $ man <command_name>

    比如你想查看 man 命令本身的使用方式,你可以输入:

    man man

    通常情况下,man 手册里面的内容都是英文的,这就要求你有一定的英文基础。man 手册的内容很多,涉及了 Linux 使用过程中的方方面面。为了便于查找,man 手册被进行了分册(分区段)处理,在 Research UNIX、BSD、OS X 和 Linux 中,手册通常被分为8个区段,安排如下:

    区段

    说明

    1

    一般命令

    2

    系统调用

    3

    库函数,涵盖了C标准函数库

    4

    特殊文件(通常是/dev中的设备)和驱动程序

    5

    文件格式和约定

    6

    游戏和屏保

    7

    杂项

    8

    系统管理命令和守护进程

    要查看相应区段的内容,就在 man 后面加上相应区段的数字即可,如:

    $ man 1 ls

    会显示第一区段中的ls命令 man 页面。

    所有的手册页遵循一个常见的布局,为了通过简单的 ASCII 文本展示而被优化,而这种情况下可能没有任何形式的高亮或字体控制。一般包括以下部分内容:

    NAME(名称)

    该命令或函数的名称,接着是一行简介。

    SYNOPSIS(概要)

    对于命令,正式的描述它如何运行,以及需要什么样的命令行参数。对于函数,介绍函数所需的参数,以及哪个头文件包含该函数的定义。

    DESCRIPTION(说明)

    命令或函数功能的文本描述。

    EXAMPLES(示例)

    常用的一些示例。

    SEE ALSO(参见)

    相关命令或函数的列表。

    也可能存在其它部分内容,但这些部分没有得到跨手册页的标准化。常见的例子包括:OPTIONS(选项),EXIT STATUS(退出状态),ENVIRONMENT(环境),BUGS(程序漏洞),FILES(文件),AUTHOR(作者),REPORTING BUGS(已知漏洞),HISTORY(历史)和 COPYRIGHT(版权)。

    通常 man 手册中的内容很多,你可能不太容易找到你想要的结果,不过幸运的是你可以在 man 中使用搜索/<你要搜索的关键字>,查找完毕后你可以使用n键切换到下一个关键字所在处,shift+n为上一个关键字所在处。使用Space(空格键)翻页,Enter(回车键)向下滚动一行,或者使用k,j(vim 编辑器的移动键)进行向前向后滚动一行。按下h键为显示使用帮助(因为 man 使用 less 作为阅读器,实为less工具的帮助),按下q退出。

    想要获得更详细的帮助,你还可以使用info命令,不过通常使用man就足够了。如果你知道某个命令的作用,只是想快速查看一些它的某个具体参数的作用,那么你可以使用--help参数,大部分命令都会带有这个参数,如:

    $ ls --help

     

     

    2.1 查看用户

    请打开终端,输入命令:

    $ who am i 或者 $ who mom likes

    输出的第一列表示打开当前伪终端的用户的用户名(要查看当前登录用户的用户名,去掉空格直接使用 whoami 即可),第二列的 pts/0 中 pts 表示伪终端,所谓伪是相对于 /dev/tty 设备而言的,还记得上一节讲终端时的那七个使用 [Ctrl]+[Alt]+[F1]~[F7]进行切换的 /dev/tty 设备么,这是“真终端”,伪终端就是当你在图形用户界面使用 /dev/tty7 时每打开一个终端就会产生一个伪终端, pts/0 后面那个数字就表示打开的伪终端序号,你可以尝试再打开一个终端,然后在里面输入 who am i ,看第二列是不是就变成 pts/1 了,第三列则表示当前伪终端的启动时间。

    who 命令其它常用参数

    参数

    说明

    -a

    打印能打印的全部

    -d

    打印死掉的进程

    -m

    同am i,mom likes

    -q

    打印当前登录用户数及用户名

    -u

    打印当前登录用户登录信息

    -r

    打印运行等级

     

     

    2.2 创建用户

    在 Linux 系统里, root 账户拥有整个系统至高无上的权利,比如 新建/添加 用户。

    root 权限,系统权限的一种,与 SYSTEM 权限可以理解成一个概念,但高于 Administrator 权限,root 是 Linux 和 UNIX 系统中的超级管理员用户帐户,该帐户拥有整个系统至高无上的权力,所有对象他都可以操作,所以很多黑客在入侵系统的时候,都要把权限提升到 root 权限,用 Windows 的方法理解也就是将自己的非法帐户添加到 Administrators 用户组。更比如安卓操作系统中(基于 Linux 内核)获得 root 权限之后就意味着已经获得了手机的最高权限,这时候你可以对手机中的任何文件(包括系统文件)执行所有增、删、改、查的操作。

    我们一般登录系统时都是以普通账户的身份登录的,要创建用户需要 root 权限,这里就要用到 sudo 这个命令了。不过使用这个命令有两个大前提,一是你要知道当前登录用户的密码,二是当前用户必须在 sudo 用户组。shiyanlou 用户也属于 sudo 用户组(稍后会介绍如何查看和添加用户组)。

    su,su- 与 sudo

    需要注意 Linux 环境下输入密码是不会显示的。

    su <user> 可以切换到用户 user,执行时需要输入目标用户的密码,sudo <cmd> 可以以特权级别运行 cmd 命令,需要当前用户属于 sudo 组,且需要输入当前用户的密码。su - <user> 命令也是切换用户,同时环境变量也会跟着改变成目标用户的环境变量。

    现在我们新建一个叫 lilei 的用户:

    $ sudo adduser lilei

    实验楼的环境目前设置为 shiyanlou 用户执行 sudo 不需要输入密码,通常此处需要按照提示输入 shiyanlou 密码(Linux 下密码输入是不显示任何内容的),shiyanlou 用户密码可以通过 sudo passwd shiyanlou 命令进行设置。然后是给 lilei 用户设置密码,后面的选项的一些内容你可以选择直接回车使用默认值:

    这个命令不但可以添加用户到系统,同时也会默认为新用户创建 home 目录:

    $ ls /home

    现在你已经创建好一个用户,并且你可以使用你创建的用户登录了,使用如下命令切换登录用户:

    $ su -l lilei

    输入刚刚设置的 lilei 的密码,然后输入如下命令并查看输出:

    $ who am i $ whoami $ pwd

    退出当前用户跟退出终端一样可以使用 exit 命令或者使用快捷键 Ctrl+d。

     

     

     

    2.3 用户组

    在 Linux 里面每个用户都有一个归属(用户组),用户组简单地理解就是一组用户的集合,它们共享一些资源和权限,同时拥有私有资源,就跟家的形式差不多,你的兄弟姐妹(不同的用户)属于同一个家(用户组),你们可以共同拥有这个家(共享资源),爸妈对待你们都一样(共享权限),你偶尔写写日记,其他人未经允许不能查看(私有资源和权限)。当然一个用户是可以属于多个用户组的,正如你既属于家庭,又属于学校或公司。

    在 Linux 里面如何知道自己属于哪些用户组呢?

    方法一:使用 groups 命令

    $ groups shiyanlou

    其中冒号之前表示用户,后面表示该用户所属的用户组。这里可以看到 shiyanlou 用户属于 shiyanlou 用户组,每次新建用户如果不指定用户组的话,默认会自动创建一个与用户名相同的用户组(差不多就相当于家长的意思,或者说是老总)。默认情况下在 sudo 用户组里的可以使用 sudo 命令获得 root 权限。shiyanlou 用户也可以使用 sudo 命令,为什么这里没有显示在 sudo 用户组里呢?可以查看下 /etc/sudoers.d/shiyanlou 文件,我们在 /etc/sudoers.d 目录下创建了这个文件,从而给 shiyanlou 用户赋予了 sudo 权限:

    方法二:查看 /etc/group 文件

    $ cat /etc/group | sort

    这里 cat 命令用于读取指定文件的内容并打印到终端输出,后面会详细讲它的使用。 | sort 表示将读取的文本进行一个字典排序再输出,然后你将看到如下一堆输出,你可以在最下面看到 shiyanlou 的用户组信息:

    没找到,没关系,你可以使用命令过滤掉一些你不想看到的结果:

    $ cat /etc/group | grep -E "shiyanlou"

    /etc/group 文件格式说明

    /etc/group 的内容包括用户组(Group)、用户组口令、GID 及该用户组所包含的用户(User),每个用户组一条记录。格式如下:

    group_name:password:GID:user_list

    你看到上面的 password 字段为一个 x 并不是说密码就是它,只是表示密码不可见而已。

    这里需要注意,如果用户主用户组,即用户的 GID 等于用户组的 GID,那么最后一个字段 user_list 就是空的,比如 shiyanlou 用户,在 /etc/group 中的 shiyanlou 用户组后面是不会显示的。lilei 用户,在 /etc/group 中的 lilei 用户组后面是不会显示的。

    将其它用户加入 sudo 用户组

    默认情况下新创建的用户是不具有 root 权限的,也不在 sudo 用户组,可以让其加入 sudo 用户组从而获取 root 权限:

    # 注意 Linux 上输入密码是不会显示的 $ su -l lilei $ sudo ls

    会提示 lilei 不在 sudoers 文件中,意思就是 lilei 不在 sudo 用户组中,至于 sudoers 文件(/etc/sudoers)你现在最好不要动它,操作不慎会导致比较麻烦的后果。

    使用 usermod 命令可以为用户添加用户组,同样使用该命令你必需有 root 权限,你可以直接使用 root 用户为其它用户添加用户组,或者用其它已经在 sudo 用户组的用户使用 sudo 命令获取权限来执行该命令。

    这里我用 shiyanlou 用户执行 sudo 命令将 lilei 添加到 sudo 用户组,让它也可以使用 sudo 命令获得 root 权限:

    $ su shiyanlou # 此处需要输入 shiyanlou 用户密码,shiyanlou 的密码可以通过 `sudo passwd shiyanlou` 进行设置。 $ groups lilei $ sudo usermod -G sudo lilei $ groups lilei

    然后你再切换回 lilei 用户,现在就可以使用 sudo 获取 root 权限了。

     

     

    2.4 删除用户

    删除用户是很简单的事:

    $ sudo deluser lilei --remove-home

     

    3.1 查看文件权限

    我们之前已经很多次用到 ls 命令了,如你所见,我们用它来列出并显示当前目录下的文件,当然这是在不带任何参数的情况下,它能做的当然不止这么多,现在我们就要用它来查看文件权限。

    使用较长格式列出文件:

    $ ls -l

    你可能除了知道最后面那一项是文件名之外,其它项就不太清楚了,那么到底是什么意思呢:

     

    可能你还是不太明白,比如第一项文件类型和权限那一堆东西具体指什么,链接又是什么,何为最后修改时间,下面一一道来:

    • 文件类型

    关于文件类型,这里有一点你必需时刻牢记 Linux 里面一切皆文件,正因为这一点才有了设备文件( /dev 目录下有各种设备文件,大都跟具体的硬件设备相关)这一说。 socket:网络套接字,具体是什么,感兴趣的用户可以自己去了解或期待实验楼的后续相关课程。pipe 管道,这个东西很重要,我们以后将会讨论到,这里你先知道有它的存在即可。软链接文件:链接文件是分为两种的,另一种当然是“硬链接”(硬链接不常用,具体内容不作为本课程讨论重点,而软链接等同于 Windows 上的快捷方式,你记住这一点就够了)。

    • 文件权限

    读权限,表示你可以使用 cat <file name> 之类的命令来读取某个文件的内容;写权限,表示你可以编辑和修改某个文件; 执行权限,通常指可以运行的二进制程序文件或者脚本文件,如同 Windows 上的 exe 后缀的文件,不过 Linux 上不是通过文件后缀名来区分文件的类型。你需要注意的一点是,一个目录同时具有读权限和执行权限才可以打开并查看内部文件,而一个目录要有写权限才允许在其中创建其它文件,这是因为目录文件实际保存着该目录里面的文件的列表等信息。

    所有者权限,这一点相信你应该明白了,至于所属用户组权限,是指你所在的用户组中的所有其它用户对于该文件的权限,比如,你有一个 iPad,那么这个用户组权限就决定了你的兄弟姐妹有没有权限使用它破坏它和占有它。

    • 链接数

    链接到该文件所在的 inode 结点的文件名数目(关于这个概念涉及到 Linux 文件系统的相关概念知识,不在本课程的讨论范围,感兴趣的用户可以自己去了解)。

    • 文件大小

    以 inode 结点大小为单位来表示的文件大小,你可以给 ls 加上 -lh 参数来更直观的查看文件的大小。

    明白了文件权限的一些概念,我们顺带补充一下关于 ls 命令的一些其它常用的用法:

    • 显示除了 .(当前目录)和 ..(上一级目录)之外的所有文件,包括隐藏文件(Linux 下以 . 开头的文件为隐藏文件)。

    $ ls -A

    当然,你可以同时使用 -A 和 -l 参数:

    $ ls -Al

    查看某一个目录的完整属性,而不是显示目录里面的文件属性:

    $ ls -dl <目录名>

    • 显示所有文件大小,并以普通人类能看懂的方式呈现:

    $ ls -AsSh

    其中小 s 为显示文件大小,大 S 为按文件大小排序,若需要知道如何按其它方式排序,请使用“man”命令查询。

     

     

    3.2 变更文件所有者

    若前面已经执行删除lilei用户的命令,这里重新创建一下。

    假设目前是 lilei 用户登录,新建一个文件,命名为 “ iphone6 ”:

    # 注意当前的用户必须是 lilei # 如果是 shiyanlou 用户需要切换到 lilei(如果之前已经删除需要重新创建下) $ su lilei $ cd /home/lilei $ touch iphone6

    可见文件所有者是 lilei :

    现在,换回到 shiyanlou 用户身份,使用以下命令变更文件所有者为 shiyanlou :

    # 需要切换到 shiyanlou 用户执行以下操作 $ cd /home/lilei $ ls iphone6 $ sudo chown shiyanlou iphone6

    现在查看,发现 文件所有者成功修改为 shiyanlou :

     

     

     

    3.3 修改文件权限

    如果你有一个自己的文件不想被其他用户读、写、执行,那么就需要对文件的权限做修改,这里有两种方式:

    • 方式一:二进制数字表示

    每个文件的三组权限(拥有者,所属用户组,其他用户,记住这个顺序是一定的)对应一个 " rwx ",也就是一个 “ 7 ” ,所以如果我要将文件“ iphone6 ”的权限改为只有我自己可以用那么就这样:

    为了演示,我先在文件里加点内容:

    $ echo "echo \"hello shiyanlou\"" > iphone6

    然后修改权限:

    $ chmod 600 iphone6

    现在,其他用户已经不能读这个“ iphone6 ”文件了:

    • 方式二:加减赋值操作

    完成上述相同的效果,你可以:

    $ chmod go-rw iphone6

    g、o 还有 u 分别表示 group、others 和 user,+ 和 - 分别表示增加和去掉相应的权限

     

     

    四、更多

    adduser 和 useradd 的区别是什么?

    答:useradd 只创建用户,创建完了用 passwd lilei 去设置新用户的密码。adduser 会创建用户,创建目录,创建密码(提示你设置),做这一系列的操作。其实 useradd、userdel 这类操作更像是一种命令,执行完了就返回。而 adduser 更像是一种程序,需要你输入、确定等一系列操作。

    Linux 还有一些关于隐藏权限和特殊权限的内容,想全面了解 Linux 权限管理这部分内容的用户可以通过其它方式学习。

     

     

    1. FHS 标准

    Linux 的目录结构说复杂很复杂,说简单也很简单。复杂在于,因为系统的正常运行是以目录结构为基础的,对于初学者来说里面大部分目录都不知道其作用,重要与否,特别对于那些曾经的重度 Windows 用户,他们会纠结很长时间,关于我安装的软件在哪里这类问题。说它简单是因为,其中大部分目录结构是规定好了的(FHS 标准),是死的,当你掌握后,你在里面的一切操作都会变得井然有序。

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

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

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

    FHS_2.3 标准文档

    如果觉得图片不清晰,建议另存为到本地放大查看:

    如果你觉得看这个不明白,那么可以试试最真实最直观的方式,执行如下命令:

    $ tree /

    如果提示" command not found ",就先安装:

    # 因为我们的环境的原因,每次新启动实验会清除系统恢复到初始状态,所以需要手动更新软件包索引,以便我们安装时能找到相应软件包的源。 sudo apt-get update sudo apt-get install tree

    关于上面提到的 FHS,这里还有个很重要的内容你一定要明白,FHS 是根据以往无数 Linux 用户和开发者的经验总结出来的,并且会维持更新,FHS 依据文件系统使用的频繁与否以及是否允许用户随意改动(注意,不是不能,学习过程中,不要怕这些),将目录定义为四种交互作用的形态,如下表所示:

     

     

     

    2. 目录路径

    路径

    有人可能不明白这路径是指什么,有什么用。顾名思义,路径就是你要去哪儿的路线嘛。如果你想进入某个具体的目录或者想获得某个目录的文件(目录本身也是文件)那就得用路径来找到了。

    使用 cd 命令可以切换目录,在 Linux 里面使用 . 表示当前目录,.. 表示上一级目录(注意,我们上一节介绍过的,以 . 开头的文件都是隐藏文件,所以这两个目录必然也是隐藏的,你可以使用 ls -a 命令查看隐藏文件), - 表示上一次所在目录,~ 通常表示当前用户的 home 目录。使用 pwd 命令可以获取当前所在路径(绝对路径)。

    进入上一级目录:

    $ cd ..

    进入你的 home 目录:

    $ cd ~ # 或者 cd /home/<你的用户名>

    使用 pwd 获取当前路径:

    $ pwd

    绝对路径

    关于绝对路径,简单地说就是以根" / "目录为起点的完整路径,以你所要到的目录为终点,表现形式如: /usr/local/bin,表示根目录下的 usr 目录中的 local 目录中的 bin目录。

    相对路径

    相对路径,也就是相对于你当前的目录的路径,相对路径是以当前目录 . 为起点,以你所要到的目录为终点,表现形式如: usr/local/bin (这里假设你当前目录为根目录)。你可能注意到,我们表示相对路径实际并没有加上表示当前目录的那个 . ,而是直接以目录名开头,因为这个 usr 目录为 / 目录下的子目录,是可以省略这个 . 的(以后会讲到一个类似不能省略的情况);如果是当前目录的上一级目录,则需要使用 ..,比如你当前目录为 home 目录,根目录就应该表示为 ../../ ,表示上一级目录( home目录)的上一级目录( / 目录)。

    下面我们以你的 home目录为起点,分别以绝对路径和相对路径的方式进入 /usr/local/bin 目录:

    # 绝对路径 $ cd /usr/local/bin # 相对路径 $ cd ../../usr/local/bin

    进入一个目录,可以使用绝对路径也可以使用相对路径,那我们应该在什么时候选择正确的方式进入某个目录呢。就是凭直觉嘛,你觉得怎样方便就使用哪一个,而不用特意只使用某一种。比如假设我当前在 /usr/local/bin 目录,我想进入上一级的 local 目录你说是使用 cd .. 方便还是 cd /usr/local 方便?而如果要进入的是 usr 目录,那么 cd /usr ,就比 cd ../.. 方便一点了。

    提示:在进行目录切换的过程中请多使用 Tab 键自动补全,可避免输入错误,连续按两次 Tab 可以显示全部候选结果。

     

     

    新建空白文件

    使用 touch 命令创建空白文件,关于 touch 命令,其主要作用是来更改已有文件的时间戳的(比如,最近访问时间,最近修改时间),但其在不加任何参数的情况下,只指定一个文件名,则可以创建一个指定文件名的空白文件(不会覆盖已有同名文件),当然你也可以同时指定该文件的时间戳,更多关于 touch 命令的用法,会在下一讲文件搜索中涉及。

    创建名为 test 的空白文件,因为在其它目录没有权限,所以需要先 cd ~ 切换回用户的/home/shiyanlou 目录:

    $ cd /home/shiyanlou $ touch test

    新建目录

    使用 mkdir(make directories)命令可以创建一个空目录,也可同时指定创建目录的权限属性。

    创建名为“ mydir ”的空目录:

    $ mkdir mydir

    使用 -p 参数,同时创建父目录(如果不存在该父目录),如下我们同时创建一个多级目录(这在安装软件、配置安装路径时非常有用):

    $ mkdir -p father/son/grandson

    后面的目录路径,以绝对路径的方式表示也是可以的。

     

     

     

    2. 复制

    复制文件

    使用 cp(copy)命令复制一个文件到指定目录。

    将之前创建的“ test ”文件复制到“ /home/shiyanlou/father/son/grandson ”目录中:

    $ cp test father/son/grandson

    是不是很方便啊,如果在图形界面则需要先在源目录复制文件,再进到目的目录粘贴文件,而命令行操作步骤就一步到位了嘛。

    复制目录

    如果直接使用 cp 命令复制一个目录的话,会出现如下错误:

    要成功复制目录需要加上 -r 或者 -R 参数,表示递归复制,就是说有点“株连九族”的意思:

    $ cd /home/shiyanlou $ mkdir family $ cp -r father family

     

     

     

    3. 删除

    删除文件

    使用 rm(remove files or directories)命令删除一个文件:

    $ rm test

    有时候你会遇到想要删除一些为只读权限的文件,直接使用 rm 删除会显示一个提示,如下:

    你如果想忽略这提示,直接删除文件,可以使用 -f 参数强制删除:

    $ rm -f test

    删除目录

    跟复制目录一样,要删除一个目录,也需要加上 -r 或 -R 参数:

    $ rm -r family

     

     

     

     

    4. 移动文件与文件重命名

    移动文件

    使用 mv(move or rename files)命令移动文件(剪切)。将文件“ file1 ”移动到 Documents 目录:

    mv 源目录文件 目的目录:

    $ mkdir Documents $ touch file1 $ mv file1 Documents

    重命名文件

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

    mv 旧的文件名 新的文件名:

    $ mv file1 myfile

    批量重命名

    要实现批量重命名,mv 命令就有点力不从心了,我们可以使用一个看起来更专业的命令 rename 来实现。不过它要用 perl 正则表达式来作为参数,关于正则表达式我们要在后面才会介绍到,这里只做演示,你只要记得这个 rename 命令可以批量重命名就好了,以后再重新学习也不会有任何问题,毕竟你已经掌握了一个更常用的 mv 命令。

    $ cd /home/shiyanlou/ # 使用通配符批量创建 5 个文件: $ touch file{1..5}.txt # 批量将这 5 个后缀为 .txt 的文本文件重命名为以 .c 为后缀的文件: $ rename 's/\.txt/\.c/' *.txt # 批量将这 5 个文件,文件名和后缀改为大写: $ rename 'y/a-z/A-Z/' *.c

    简单解释一下上面的命令,rename 是先使用第二个参数的通配符匹配所有后缀为 .txt的文件,然后使用第一个参数提供的正则表达式将匹配的这些文件的 .txt 后缀替换为 .c,这一点在我们后面学习了 sed 命令后,相信你会更好地理解。

     

     

    5. 查看文件

    使用 cat,tac 和 nl 命令查看文件

    前两个命令都是用来打印文件内容到标准输出(终端),其中 cat 为正序显示,tac 为倒序显示。

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

    比如我们要查看之前从 /etc 目录下拷贝来的 passwd 文件:

    $ cd /home/shiyanlou $ cp /etc/passwd passwd $ cat passwd

    可以加上 -n 参数显示行号:

    $ cat -n passwd

    nl 命令,添加行号并打印,这是个比 cat -n 更专业的行号打印命令。

    这里简单列举它的常用的几个参数:

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

    你会发现使用这几个命令,默认的终端窗口大小,一屏显示不完文本的内容,得用鼠标拖动滚动条或者滑动滚轮才能继续往下翻页,要是可以直接使用键盘操作翻页就好了,那么你就可以使用下面要介绍的命令。

    使用 more 和 less 命令分页查看文件

    如果说上面的 cat 是用来快速查看一个文件的内容的,那么这个 more 和 less 就是天生用来"阅读"一个文件的内容的,比如说 man 手册内部就是使用的 less 来显示内容。其中 more 命令比较简单,只能向一个方向滚动,而 less 为基于 more 和 vi (一个强大的编辑器,我们有单独的课程来让你学习)开发,功能更强大。less 的使用基本和 more一致,具体使用请查看 man 手册,这里只介绍 more 命令的使用。

    使用 more 命令打开 passwd 文件:

    $ more passwd

    打开后默认只显示一屏内容,终端底部显示当前阅读的进度。可以使用 Enter 键向下滚动一行,使用 Space 键向下滚动一屏,按下 h 显示帮助,q 退出。

    使用 head 和 tail 命令查看文件

    这两个命令,那些性子比较急的人应该会喜欢,因为它们一个是只查看文件的头几行(默认为 10 行,不足 10 行则显示全部)和尾几行。还是拿 passwd 文件举例,比如当我们想要查看最近新增加的用户,那么我们可以查看这个 /etc/passwd 文件,不过我们前面也看到了,这个文件里面一大堆乱糟糟的东西,看起来实在费神啊。因为系统新增加一个用户,会将用户的信息添加到 passwd 文件的最后,那么这时候我们就可以使用 tail 命令了:

    $ tail /etc/passwd

    甚至更直接的只看一行, 加上 -n 参数,后面紧跟行数:

    $ tail -n 1 /etc/passwd

    关于 tail 命令,不得不提的还有它一个很牛的参数 -f,这个参数可以实现不停地读取某个文件的内容并显示。这可以让我们动态查看日志,达到实时监视的目的。不过我不会在这门基础课程中介绍它的更多细节,感兴趣的用户可以自己去了解。

     

     

    6. 查看文件类型

    前面我提到过,在 Linux 中文件的类型不是根据文件后缀来判断的,我们通常使用 file 命令查看文件的类型:

    $ file /bin/ls

    说明这是一个可执行文件,运行在 64 位平台,并使用了动态链接文件(共享库)。

    隐藏环境

     

     

     

    二、环境变量

    变量

    要解释环境变量,得先明白变量是什么,准确的说应该是 Shell 变量,所谓变量就是计算机中用于记录一个值(不一定是数值,也可以是字符或字符串)的符号,而这些符号将用于不同的运算处理中。通常变量与值是一对一的关系,可以通过表达式读取它的值并赋值给其它变量,也可以直接指定数值赋值给任意变量。为了便于运算和处理,大部分的编程语言会区分变量的类型,用于分别记录数值、字符或者字符串等等数据类型。Shell 中的变量也基本如此,有不同类型(但不用专门指定类型名),可以参与运算,有作用域限定。

    变量的作用域即变量的有效范围(比如一个函数中、一个源文件中或者全局范围),在该范围内只能有一个同名变量。一旦离开则该变量无效,如同不存在这个变量一般。

    在 Shell 中如何创建一个变量,如何给变量赋值和如何读取变量的值呢?这部分内容会在 bash 脚本编程 这门课中详细介绍,这里我简单举例说明一下:

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

    $ declare tmp

    其实也可以不用 declare 预声明一个变量,直接即用即创建,这里只是告诉你 declare 的作用,这在创建其它指定类型的变量(如数组)时会用到。

    使用 = 号赋值运算符,将变量 tmp 赋值为 shiyanlou:

    $ tmp=shiyanlou

    读取变量的值,使用 echo 命令和 $ 符号($ 符号用于表示引用一个变量的值,初学者经常忘记输入):

    $ echo $tmp

    注意:并不是任何形式的变量名都是可用的,变量名只能是英文字母、数字或者下划线,且不能以数字作为开头。

     

     

    1. 环境变量

    简单理解了变量的概念,就很容易理解环境变量了。环境变量的作用域比自定义变量的要大,如 Shell 的环境变量作用于自身和它的子进程。在所有的 UNIX 和类 UNIX 系统中,每个进程都有其各自的环境变量设置,且默认情况下,当一个进程被创建时,除了创建过程中明确指定的话,它将继承其父进程的绝大部分环境设置。Shell 程序也作为一个进程运行在操作系统之上,而我们在 Shell 中运行的大部分命令都将以 Shell 的子进程的方式运行。

    通常我们会涉及到的变量类型有三种:

    • 当前 Shell 进程私有用户自定义变量,如上面我们创建的 tmp 变量,只在当前 Shell 中有效。
    • Shell 本身内建的变量。
    • 从自定义变量导出的环境变量。

    也有三个与上述三种环境变量相关的命令:set,env,export。这三个命令很相似,都是用于打印环境变量信息,区别在于涉及的变量范围不同。详见下表:

    命 令

    说 明

    set

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

    env

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

    export

    显示从 Shell 中导出成环境变量的变量,也能通过它将自定义变量导出为环境变量。

    你可以更直观的使用 vimdiff 工具比较一下它们之间的差别:

    $ temp=shiyanlou $ export temp_env=shiyanlou $ env|sort>env.txt $ export|sort>export.txt $ set|sort>set.txt

    上述操作将命令输出通过管道 | 使用 sort 命令排序,再重定向到对象文本文件中。

    $ vimdiff env.txt export.txt set.txt

    使用 vimdiff 工具比较导出的几个文件的内容:

    关于哪些变量是环境变量,可以简单地理解成在当前进程的子进程有效则为环境变量,否则不是(有些人也将所有变量统称为环境变量,只是以全局环境变量和局部环境变量进行区分,我们只要理解它们的实质区别即可)。我们这里用 export 命令来体会一下,先在 Shell 中设置一个变量 temp=shiyanlou,然后再新创建一个子 Shell 查看 temp 变量的值:

    注意:为了与普通变量区分,通常我们习惯将环境变量名设为大写。

    永久生效

    但是问题来了,当你关机后,或者关闭当前的 shell 之后,环境变量就没了啊。怎么才能让环境变量永久生效呢?

    按变量的生存周期来划分,Linux 变量可分为两类:

    1. 永久的:需要修改配置文件,变量永久生效;
    2. 临时的:使用 export 命令行声明即可,变量在关闭 shell 时失效。

    这里介绍两个重要文件 /etc/bashrc(有的 Linux 没有这个文件) 和 /etc/profile ,它们分别存放的是 shell 变量和环境变量。还有要注意区别的是每个用户目录下的一个隐藏文件:

    .profile 可以用 ls -a 查看 cd /home/shiyanlou ls -a

    这个 .profile 只对当前用户永久生效。而写在 /etc/profile 里面的是对所有用户永久生效,所以如果想要添加一个永久生效的环境变量,只需要打开 /etc/profile,在最后加上你想添加的环境变量就好啦。

     

    2. 命令的查找路径与顺序

    你可能很早之前就有疑问,我们在 Shell 中输入一个命令,Shell 是怎么知道去哪找到这个命令然后执行的呢?这是通过环境变量 PATH 来进行搜索的,熟悉 Windows 的用户可能知道 Windows 中的也是有这么一个 PATH 环境变量。这个 PATH 里面就保存了 Shell 中执行的命令的搜索路径。

    查看 PATH 环境变量的内容:

    $ echo $PATH

    默认情况下你会看到如下输出:

    /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games

    如果你还记得 Linux 目录结构那一节的内容,你就应该知道上面这些目录下放的是哪一类文件了。通常这一类目录下放的都是可执行文件,当我们在 Shell 中执行一个命令时,系统就会按照 PATH 中设定的路径按照顺序依次到目录中去查找,如果存在同名的命令,则执行先找到的那个。

    下面我们将练习创建一个最简单的可执行 Shell 脚本和一个使用 C 语言创建的“ hello world ”程序,如果这两部分内容你之前没有学习过,那么你可以进行一个入门学习: C 语言入门教程 高级 Bash 脚本编程指南 Linux Shell Scripting Tutorial (LSST) v2.0 。

    创建一个 Shell 脚本文件:

    $ cd /home/shiyanlou $ touch hello_shell.sh $ gedit hello_shell.sh

    在脚本中添加如下内容,保存并退出(注意不要省掉第一行,这不是注释,论坛有用户反映有语法错误,就是因为没有了第一行):

    #!/bin/bash for ((i=0; i<10; i++));do echo "hello shell" done exit 0

    为文件添加可执行权限:

    $ chmod 755 hello_shell.sh

    执行脚本:

    $ cd /home/shiyanlou $ ./hello_shell.sh

    创建一个 C 语言“ hello world ”程序:

    $ cd /home/shiyanlou $ gedit hello_world.c

    #include <stdio.h> int main(void) { printf("hello world!\n"); return 0; }

    保存后使用 gcc 生成可执行文件:

    $ gcc -o hello_world hello_world.c

    gcc 生成二进制文件默认具有可执行权限,不需要修改

    在 /home/shiyanlou 家目录创建一个 mybin 目录,并将上述 hello_shell.sh 和 hello_world 文件移动到其中:

    $ cd /home/shiyanlou $ mkdir mybin $ mv hello_shell.sh hello_world mybin/

    现在你可以在 mybin 目录中分别运行你刚刚创建的两个程序:

    $ cd mybin $ ./hello_shell.sh $ ./hello_world

    回到上一级目录,也就是 shiyanlou 家目录,当再想运行那两个程序时,会发现提示命令找不到,除非加上命令的完整路径,但那样很不方便,如何做到像使用系统命令一样执行自己创建的脚本文件或者程序呢?那就要将命令所在路径添加到 PATH 环境变量

     

     

    3. 添加自定义路径到“ PATH ”环境变量

    在前面我们应该注意到 PATH 里面的路径是以 : 作为分割符的,所以我们可以这样添加自定义路径:

    $ PATH=$PATH:/home/shiyanlou/mybin

    注意这里一定要使用绝对路径。

    现在你就可以在任意目录执行那两个命令了(注意需要去掉前面的 ./)。你可能会意识到这样还并没有很好的解决问题,因为我给 PATH 环境变量追加了一个路径,它也只是在当前 Shell 有效,我一旦退出终端,再打开就会发现又失效了。有没有方法让添加的环境变量全局有效?或者每次启动 Shell 时自动执行上面添加自定义路径到 PATH 的命令?下面我们就来说说后一种方式——让它自动执行。

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

    我们可以简单地使用下面命令直接添加内容到 .zshrc 中:

    $ echo "PATH=$PATH:/home/shiyanlou/mybin" >> .zshrc

    上述命令中 >> 表示将标准输出以追加的方式重定向到一个文件中,注意前面用到的 > 是以覆盖的方式重定向到一个文件中,使用的时候一定要注意分辨。在指定文件不存在的情况下都会创建新的文件。

     

     

    4. 修改和删除已有变量

    变量修改

    变量的修改有以下几种方式:

    变量设置方式

    说明

    ${变量名#匹配字串}

    从头向后开始匹配,删除符合匹配字串的最短数据

    ${变量名##匹配字串}

    从头向后开始匹配,删除符合匹配字串的最长数据

    ${变量名%匹配字串}

    从尾向前开始匹配,删除符合匹配字串的最短数据

    ${变量名%%匹配字串}

    从尾向前开始匹配,删除符合匹配字串的最长数据

    ${变量名/旧的字串/新的字串}

    将符合旧字串的第一个字串替换为新的字串

    ${变量名//旧的字串/新的字串}

    将符合旧字串的全部字串替换为新的字串

    比如要修改我们前面添加到 PATH 的环境变量。为了避免操作失误导致命令找不到,我们先将 PATH 赋值给一个新的自定义变量 path:

    $ path=$PATH $ echo $path $ path=${path%/home/shiyanlou/mybin} # 或使用通配符,*表示任意多个任意字符 $ path=${path%*/mybin}

    变量删除

    可以使用 unset 命令删除一个环境变量:

    $ unset temp

     

    5. 如何让环境变量立即生效

    前面我们在 Shell 中修改了一个配置脚本文件之后(比如 zsh 的配置文件 home 目录下的 .zshrc),每次都要退出终端重新打开甚至重启主机之后其才能生效,很是麻烦,我们可以使用 source 命令来让其立即生效,如:

    $ cd /home/shiyanlou $ source .zshrc

    source 命令还有一个别名就是 .,上面的命令如果替换成 . 的方式就该是:

    $ . ./.zshrc

    在使用.的时候,需要注意与表示当前路径的那个点区分开。

    注意第一个点后面有一个空格,而且后面的文件必须指定完整的绝对或相对路径名,source 则不需要。

     

    三、搜索文件

    与搜索相关的命令常用的有 whereis,which,find 和 locate 。

    • whereis 简单快速

    $ whereis who $ whereis find

    你会看到 whereis find 找到了三个路径,两个可执行文件路径和一个 man 在线帮助文件所在路径,这个搜索很快,因为它并没有从硬盘中依次查找,而是直接从数据库中查询。whereis 只能搜索二进制文件(-b),man 帮助文件(-m)和源代码文件(-s)。如果想要获得更全面的搜索结果可以使用 locate 命令。

    • locate 快而全

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

    $ sudo apt-get update $ sudo apt-get install locate $ locate /etc/sh

    注意,它不只是在 /bin 目录下查找,还会自动递归子目录进行查找。

    查找 /usr/share/ 下所有 jpg 文件:

    $ locate /usr/share/\*.jpg

    注意要添加 * 号前面的反斜杠转义,否则会无法找到。

    如果想只统计数目可以加上 -c 参数,-i 参数可以忽略大小写进行查找,whereis 的 -b、-m、-s 同样可以使用。

    • which 小而精

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

    $ which man

    • find 精而细

    find 应该是这几个命令中最强大的了,它不但可以通过文件类型、文件名进行查找而且可以根据文件的属性(如文件的时间戳,文件的权限等)进行搜索。find 命令强大到,要把它讲明白至少需要单独好几节课程才行,我们这里只介绍一些常用的内容。

    这条命令表示去 /etc/ 目录下面 ,搜索名字叫做 interfaces 的文件或者目录。这是 find 命令最常见的格式,千万记住 find 的第一个参数是要搜索的地方:

    $ sudo find /etc/ -name interfaces

    注意 find 命令的路径是作为第一个参数的, 基本命令格式为 find [path] [option] [action] 。

    与时间相关的命令参数:

    参数

    说明

    -atime

    最后访问时间

    -ctime

    最后修改文件内容的时间

    -mtime

    最后修改文件属性的时间

    下面以 -mtime 参数举例:

    • -mtime n:n 为数字,表示为在 n 天之前的“一天之内”修改过的文件
    • -mtime +n:列出在 n 天之前(不包含 n 天本身)被修改过的文件
    • -mtime -n:列出在 n 天之内(包含 n 天本身)被修改过的文件
    • -newer file:file 为一个已存在的文件,列出比 file 还要新的文件名

    列出 home 目录中,当天(24 小时之内)有改动的文件:

    $ find ~ -mtime 0

    列出用户家目录下比 Code 文件夹新的文件:

    $ find ~ -newer /home/shiyanlou/Code

     

     

    •  

    使用 zip 打包文件夹:

    $ cd /home/shiyanlou $ zip -r -q -o shiyanlou.zip /home/shiyanlou/Desktop $ du -h shiyanlou.zip $ file shiyanlou.zip

    上面命令将目录 /home/shiyanlou/Desktop 打包成一个文件,并查看了打包后文件的大小和类型。第一行命令中,-r 参数表示递归打包包含子目录的全部内容,-q 参数表示为安静模式,即不向屏幕输出信息,-o,表示输出文件,需在其后紧跟打包输出文件名。后面使用 du 命令查看打包后文件的大小(后面会具体说明该命令)。

    • 设置压缩级别为 9 和 1(9 最大,1 最小),重新打包:

    $ zip -r -9 -q -o shiyanlou_9.zip /home/shiyanlou/Desktop -x ~/*.zip $ zip -r -1 -q -o shiyanlou_1.zip /home/shiyanlou/Desktop -x ~/*.zip

    这里添加了一个参数用于设置压缩级别 -[1-9],1 表示最快压缩但体积大,9 表示体积最小但耗时最久。最后那个 -x 是为了排除我们上一次创建的 zip 文件,否则又会被打包进这一次的压缩文件中,注意:这里只能使用绝对路径,否则不起作用。

    我们再用 du 命令分别查看默认压缩级别、最低、最高压缩级别及未压缩的文件的大小:

    $ du -h -d 0 *.zip ~ | sort

    通过 man 手册可知:

    • h, --human-readable(顾名思义,你可以试试不加的情况)
    • d, --max-depth(所查看文件的深度)

    这样一目了然,理论上来说默认压缩级别应该是最高的,但是由于文件不大,这里的差异不明显(几乎看不出差别),不过你在环境中操作之后看到的压缩文件大小可能跟图上的有些不同,因为系统在使用过程中,会随时生成一些缓存文件在当前用户的家目录中,这对于我们学习命令使用来说,是无关紧要的,可以忽略这些不同。

    • 创建加密 zip 包

    使用 -e 参数可以创建加密压缩包:

    $ zip -r -e -o shiyanlou_encryption.zip /home/shiyanlou/Desktop

    注意: 关于 zip 命令,因为 Windows 系统与 Linux/Unix 在文本文件格式上的一些兼容问题,比如换行符(为不可见字符),在 Windows 为 CR+LF(Carriage-Return+Line-Feed:回车加换行),而在 Linux/Unix 上为 LF(换行),所以如果在不加处理的情况下,在 Linux 上编辑的文本,在 Windows 系统上打开可能看起来是没有换行的。如果你想让你在 Linux 创建的 zip 压缩文件在 Windows 上解压后没有任何问题,那么你还需要对命令做一些修改:

    $ zip -r -l -o shiyanlou.zip /home/shiyanlou/Desktop

    需要加上 -l 参数将 LF 转换为 CR+LF 来达到以上目的。

     

    3.2 使用 unzip 命令解压缩 zip 文件

    将 shiyanlou.zip 解压到当前目录:

    $ unzip shiyanlou.zip

    使用安静模式,将文件解压到指定目录:

    $ unzip -q shiyanlou.zip -d ziptest

    上述指定目录不存在,将会自动创建。如果你不想解压只想查看压缩包的内容你可以使用 -l 参数:

    $ unzip -l shiyanlou.zip

    注意: 使用 unzip 解压文件时我们同样应该注意兼容问题,不过这里我们关心的不再是上面的问题,而是中文编码的问题,通常 Windows 系统上面创建的压缩文件,如果有有包含中文的文档或以中文作为文件名的文件时默认会采用 GBK 或其它编码,而 Linux 上面默认使用的是 UTF-8 编码,如果不加任何处理,直接解压的话可能会出现中文乱码的问题(有时候它会自动帮你处理),为了解决这个问题,我们可以在解压时指定编码类型。

    使用 -O(英文字母,大写 o)参数指定编码类型:

    unzip -O GBK 中文压缩文件.zip

     

     

     

    3.3 tar 打包工具

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

    下面先掌握 tar 命令一些基本的使用方式,即不进行压缩只是进行打包(创建归档文件)和解包的操作。

    • 创建一个 tar 包:

    $ cd /home/shiyanlou $ tar -cf shiyanlou.tar /home/shiyanlou/Desktop

    上面命令中,-c 表示创建一个 tar 包文件,-f 用于指定创建的文件名,注意文件名必须紧跟在 -f 参数之后,比如不能写成 tar -fc shiyanlou.tar,可以写成 tar -f shiyanlou.tar -c ~。你还可以加上 -v 参数以可视的的方式输出打包的文件。上面会自动去掉表示绝对路径的 /,你也可以使用 -P 保留绝对路径符。

    • 解包一个文件(-x 参数)到指定路径的已存在目录(-C 参数):

    $ mkdir tardir $ tar -xf shiyanlou.tar -C tardir

    • 只查看不解包文件 -t 参数:

    $ tar -tf shiyanlou.tar

    • 保留文件属性和跟随链接(符号链接或软链接),有时候我们使用 tar 备份文件当你在其他主机还原时希望保留文件的属性(-p 参数)和备份链接指向的源文件而不是链接本身(-h 参数):

    $ tar -cphf etc.tar /etc

    对于创建不同的压缩格式的文件,对于 tar 来说是相当简单的,需要的只是换一个参数,这里我们就以使用 gzip 工具创建 *.tar.gz 文件为例来说明。

    • 我们只需要在创建 tar 文件的基础上添加 -z 参数,使用 gzip 来压缩文件:

    $ tar -czf shiyanlou.tar.gz /home/shiyanlou/Desktop

    • 解压 *.tar.gz 文件:

    $ tar -xzf shiyanlou.tar.gz

    现在我们要使用其它的压缩工具创建或解压相应文件只需要更改一个参数即可:

    压缩文件格式

    参数

    *.tar.gz

    -z

    *.tar.xz

    -J

    *tar.bz2

    -j

    tar 命令的参数很多,不过常用的就是上述这些,需要了解更多你可以查看 man 手册获取帮助。

     

     

    3.3 tar 打包工具

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

    下面先掌握 tar 命令一些基本的使用方式,即不进行压缩只是进行打包(创建归档文件)和解包的操作。

    • 创建一个 tar 包:

    $ cd /home/shiyanlou $ tar -cf shiyanlou.tar /home/shiyanlou/Desktop

    上面命令中,-c 表示创建一个 tar 包文件,-f 用于指定创建的文件名,注意文件名必须紧跟在 -f 参数之后,比如不能写成 tar -fc shiyanlou.tar,可以写成 tar -f shiyanlou.tar -c ~。你还可以加上 -v 参数以可视的的方式输出打包的文件。上面会自动去掉表示绝对路径的 /,你也可以使用 -P 保留绝对路径符。

    • 解包一个文件(-x 参数)到指定路径的已存在目录(-C 参数):

    $ mkdir tardir $ tar -xf shiyanlou.tar -C tardir

    • 只查看不解包文件 -t 参数:

    $ tar -tf shiyanlou.tar

    • 保留文件属性和跟随链接(符号链接或软链接),有时候我们使用 tar 备份文件当你在其他主机还原时希望保留文件的属性(-p 参数)和备份链接指向的源文件而不是链接本身(-h 参数):

    $ tar -cphf etc.tar /etc

    对于创建不同的压缩格式的文件,对于 tar 来说是相当简单的,需要的只是换一个参数,这里我们就以使用 gzip 工具创建 *.tar.gz 文件为例来说明。

    • 我们只需要在创建 tar 文件的基础上添加 -z 参数,使用 gzip 来压缩文件:

    $ tar -czf shiyanlou.tar.gz /home/shiyanlou/Desktop

    • 解压 *.tar.gz 文件:

    $ tar -xzf shiyanlou.tar.gz

    现在我们要使用其它的压缩工具创建或解压相应文件只需要更改一个参数即可:

    压缩文件格式

    参数

    *.tar.gz

    -z

    *.tar.xz

    -J

    *tar.bz2

    -j

    tar 命令的参数很多,不过常用的就是上述这些,需要了解更多你可以查看 man 手册获取帮助。

     

     

     

     

    说了这么多,其实平常使用的参数并没有那么复杂,只需要记住常用的组合就可以了。 常用命令:

    • zip:
    • 打包 :zip something.zip something (目录请加 -r 参数)
    • 解包:unzip something.zip
    • 指定路径:-d 参数
    • tar:
    • 打包:tar -cf something.tar something
    • 解包:tar -xf something.tar
    • 指定路径:-C 参数

     

    二、基本操作

    2.1 查看磁盘和目录的容量

    使用 df 命令查看磁盘的容量

    $ df

    在实验楼的环境中你将看到如下的输出内容: 

    但在实际的物理主机上会更像这样:

    物理主机上的 /dev/sda2 是对应着主机硬盘的分区,后面的数字表示分区号,数字前面的字母 a 表示第几块硬盘(也可能是可移动磁盘),你如果主机上有多块硬盘则可能还会出现 /dev/sdb,/dev/sdc 这些磁盘设备都会在 /dev 目录下以文件的存在形式。

    接着你还会看到"1k-块"这个陌生的东西,它表示以磁盘块大小的方式显示容量,后面为相应的以块大小表示的已用和可用容量,在你了解 Linux 的文件系统之前这个就先不管吧,我们以一种你应该看得懂的方式展示:

    $ df -h

    现在你就可以使用命令查看你主机磁盘的使用情况了。至于挂载点如果你还记得前面第 4 节介绍 Linux 目录树结构的内容,那么你就应该能很好的理解挂载的概念,这里就不再赘述。

    使用 du 命令查看目录的容量

    这个命令前面其实已经用了很多次了:

    # 默认同样以 块 的大小展示 $ du # 加上`-h`参数,以更易读的方式展示 $ du -h

    -d参数指定查看目录的深度

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

    常用参数

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

    du(estimate file space usage)命令与df(report file system disk space usage)命令只有一字之差,希望大家注意不要弄混淆了,你可以像我这样从man手册中获取命令的完整描述,记全称就不会搞混了。

     

     

    3.1 创建虚拟磁盘

    dd 命令简介(部分说明来自dd (Unix) wiki

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

    dd的命令行语句与其他的 Linux 程序不同,因为它的命令行选项格式为选项=值,而不是更标准的--选项 值或-选项=值。dd默认从标准输入中读取,并写入到标准输出中,但可以用选项if(input file,输入文件)和of(output file,输出文件)改变。

    我们先来试试用dd命令从标准输入读入用户的输入到标准输出或者一个文件中:

    # 输出到文件 $ dd of=test bs=10 count=1 # 或者 dd if=/dev/stdin of=test bs=10 count=1 # 输出到标准输出 $ dd if=/dev/stdin of=/dev/stdout bs=10 count=1 # 注 在打完了这个命令后,继续在终端打字,作为你的输入

    上述命令从标准输入设备读入用户输入(缺省值,所以可省略)然后输出到 test 文件,bs(block size)用于指定块大小(缺省单位为 Byte,也可为其指定如'K','M','G'等单位),count用于指定块数量。如上图所示,我指定只读取总共 10 个字节的数据,当我输入了“hello shiyanlou”之后加上空格回车总共 16 个字节(一个英文字符占一个字节)内容,显然超过了设定大小。使用du和cat命令看到的写入完成文件实际内容确实只有 10 个字节(那个黑底百分号表示这里没有换行符),而其他的多余输入将被截取并保留在标准输入。

    前面说到dd在拷贝的同时还可以实现数据转换,那下面就举一个简单的例子:将输出的英文字符转换为大写再写入文件:

    $ dd if=/dev/stdin of=test bs=10 count=1 conv=ucase

    你可以在man文档中查看其他所有转换参数。

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

    通过上面一小节,你应该掌握了dd的基本使用,下面就来使用dd命令来完成创建虚拟磁盘的第一步。

    从/dev/zero设备创建一个容量为 256M 的空文件:

    $ dd if=/dev/zero of=virtual.img bs=1M count=256 $ du -h virtual.img

    然后我们要将这个文件格式化(写入文件系统),这里我们要学到一个(准确的说是一组)新的命令来完成这个需求。

    使用 mkfs 命令格式化磁盘(我们这里是自己创建的虚拟磁盘镜像)

    你可以在命令行输入 sudo mkfs 然后按下Tab键,你可以看到很多个以 mkfs 为前缀的命令,这些不同的后缀其实就是表示着不同的文件系统,可以用 mkfs 格式化成的文件系统。

    我们可以简单的使用下面的命令来将我们的虚拟磁盘镜像格式化为ext4文件系统:

    $ sudo mkfs.ext4 virtual.img

    可以看到实际 mkfs.ext4 是使用 mke2fs 来完成格式化工作的。mke2fs 的参数很多,不过我们也不会经常格式化磁盘来玩,所以就掌握这基本用法吧,等你有特殊需求时,再查看 man 文档解决。

    更多关于文件系统的知识,请查看wiki: 文件系统 ext3,ext4

    如果你想知道 Linux 支持哪些文件系统你可以输入ls -l /lib/modules/$(uname -r)/kernel/fs(我们的环境中无法查看)查看。

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

    用户在 Linux/UNIX 的机器上打开一个文件以前,包含该文件的文件系统必须先进行挂载的动作,此时用户要对该文件系统执行 mount 的指令以进行挂载。该指令通常是使用在 USB 或其他可移除存储设备上,而根目录则需要始终保持挂载的状态。又因为 Linux/UNIX 文件系统可以对应一个文件而不一定要是硬件设备,所以可以挂载一个包含文件系统的文件到目录树。

    Linux/UNIX 命令行的 mount 指令是告诉操作系统,对应的文件系统已经准备好,可以使用了,而该文件系统会对应到一个特定的点(称为挂载点)。挂载好的文件、目录、设备以及特殊文件即可提供用户使用。

    我们先来使用mount来查看下主机已经挂载的文件系统:

    $ sudo mount

    输出的结果中每一行表示一个设备或虚拟设备,每一行最前面是设备名,然后是 on 后面是挂载点,type 后面表示文件系统类型,再后面是挂载选项(比如可以在挂载时设定以只读方式挂载等等)。

    那么我们如何挂载真正的磁盘到目录树呢,mount命令的一般格式如下:

    mount [options] [source] [directory]

    一些常用操作:

    mount [-o [操作选项]] [-t 文件系统类型] [-w|--rw|--ro] [文件系统源] [挂载点]

    注意:由于实验楼的环境限制,mount 命令挂载及 umount 卸载都无法进行操作,可以简单了解这些步骤。

    现在直接来挂载我们创建的虚拟磁盘镜像到/mnt目录:

    $ mount -o loop -t ext4 virtual.img /mnt # 也可以省略挂载类型,很多时候 mount 会自动识别 # 以只读方式挂载 $ mount -o loop --ro virtual.img /mnt # 或者mount -o loop,ro virtual.img /mnt

    使用 umount 命令卸载已挂载磁盘

    注意:由于实验楼的环境限制,mount 命令挂载及 umount 卸载都无法进行操作,可以简单了解这些步骤。

    # 命令格式 sudo umount 已挂载设备名或者挂载点,如: $ sudo umount /mnt

    不过遗憾的是,由于我们环境的问题(环境中使用的 Linux 内核在编译时没有添加对 Loop device的支持),所以你将无法挂载成功:

    另外关于 loop 设备,你可能会有诸多疑问,那么请看下面来自维基百科/dev/loop的说明:

    在类 UNIX 系统中,/dev/loop(或称vnd (vnode disk)、lofi(循环文件接口))是一种伪设备,这种设备使得文件可以如同块设备一般被访问。

    在使用之前,循环设备必须与现存文件系统上的文件相关联。这种关联将提供给用户一个应用程序接口,接口将允许文件视为块特殊文件(参见设备文件系统)使用。因此,如果文件中包含一个完整的文件系统,那么这个文件就能如同磁盘设备一般被挂载。

    这种设备文件经常被用于光盘或是磁盘镜像。通过循环挂载来挂载包含文件系统的文件,便使处在这个文件系统中的文件得以被访问。这些文件将出现在挂载点目录。如果挂载目录中本身有文件,这些文件在挂载后将被禁止使用。

    使用 fdisk 为磁盘分区(关于分区的一些概念不清楚的用户请参看主引导记录

    注意:由于实验楼的环境限制,fdisk 命令无法进行操作,可以简单了解这些步骤。

    同样因为环境中没有物理磁盘,也无法创建虚拟磁盘的原因我们就无法实验练习使用该命令了,下面我将以我的物理主机为例讲解如何为磁盘分区。

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

    输出结果中开头显示了我主机上的磁盘的一些信息,包括容量扇区数,扇区大小,I/O 大小等信息。

    我们重点看一下中间的分区信息,/dev/sda1,/dev/sda2 为主分区分别安装了 Windows 和 Linux 操作系统,/dev/sda3 为交换分区(可以理解为虚拟内存),/dev/sda4 为扩展分区其中包含 /dev/sda5,/dev/sda6,/dev/sda7,/dev/sda8 四个逻辑分区,因为主机上有几个分区之间有空隙,没有对齐边界扇区,所以分区之间不是完全连续的。

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

    在进行操作前我们首先应先规划好我们的分区方案,这里我将在使用 128M(可用 127M 左右)的虚拟磁盘镜像创建一个 30M 的主分区剩余部分为扩展分区包含 2 个大约 45M 的逻辑分区。

    操作完成后输入p查看结果如下:

    最后不要忘记输入w写入分区表。

    使用 losetup 命令建立镜像与回环设备的关联

    注意:由于实验楼的环境限制,losetup 命令无法进行操作,可以简单了解这些步骤。

    同样因为环境原因中没有物理磁盘,也没有 loop device 的原因我们就无法实验练习使用该命令了,下面我将以我的物理主机为例讲解。

    $ sudo losetup /dev/loop0 virtual.img # 如果提示设备忙你也可以使用其它的回环设备,"ls /dev/loop*"参看所有回环设备 # 解除设备关联 $ sudo losetup -d /dev/loop0

    然后再使用mkfs格式化各分区(前面我们是格式化整个虚拟磁盘镜像文件或磁盘),不过格式化之前,我们还要为各分区建立虚拟设备的映射,用到kpartx工具,需要先安装:

    $ sudo apt-get install kpartx $ sudo kpartx -av /dev/loop0 # 取消映射 $ sudo kpartx -dv /dev/loop0

    接着再是格式化,我们将其全部格式化为 ext4:

    $ sudo mkfs.ext4 -q /dev/mapper/loop0p1 $ sudo mkfs.ext4 -q /dev/mapper/loop0p5 $ sudo mkfs.ext4 -q /dev/mapper/loop0p6

    格式化完成后在/media目录下新建四个空目录用于挂载虚拟磁盘:

    $ mkdir -p /media/virtualdisk_{1..3}

    # 挂载磁盘分区 $ sudo mount /dev/mapper/loop0p1 /media/virtualdisk_1 $ sudo mount /dev/mapper/loop0p5 /media/virtualdisk_2 $ sudo mount /dev/mapper/loop0p6 /media/virtualdisk_3 # 卸载磁盘分区 $ sudo umount /dev/mapper/loop0p1 $ sudo umount /dev/mapper/loop0p5 $ sudo umount /dev/mapper/loop0p6

    然后:

    $ df -h

    轻松一下

    cowsay命令,可以让你在终端里以一种动物说话的形式打印出一段话。

    # 更新软件包 $ sudo apt update # 安装 $ sudo apt install -y cowsay # 默认是一只牛 $ cowsay hello shiyanlou # 加上'-l'参数打印所有支持的动物(其实不只是动物)种类 $ cowsay -l # 使用'-f'参数选择动物种类 $ cowsay -f elephant hello shiyanlou # 安装 fortune-zh $ sudo apt-get install fortune-zh # 此外它还可以结合我们之前的作业讲过的 fortune 命令一起使用 $ /usr/games/fortune | cowsay -f daemon

     

     

     

    什么是内建命令,什么是外部命令呢?这和帮助命令又有什么关系呢?

    因为有一些查看帮助的工具在内建命令与外建命令上是有区别对待的。

    内建命令实际上是 shell 程序的一部分,其中包含的是一些比较简单的 Linux 系统命令,这些命令是写在bash源码的builtins里面的,由 shell 程序识别并在 shell 程序内部完成运行,通常在 Linux 系统加载运行时 shell 就被加载并驻留在系统内存中。而且解析内部命令 shell 不需要创建子进程,因此其执行速度比外部命令快。比如:history、cd、exit 等等。

    外部命令是 Linux 系统中的实用程序部分,因为实用程序的功能通常都比较强大,所以其包含的程序量也会很大,在系统加载时并不随系统一起被加载到内存中,而是在需要时才将其调入内存。虽然其不包含在 shell 中,但是其命令执行过程是由 shell 程序控制的。外部命令是在 Bash 之外额外安装的,通常放在/bin,/usr/bin,/sbin,/usr/sbin等等。比如:ls、vi等。

    简单来说就是:一个是天生自带的天赋技能,一个是后天得来的附加技能。我们可以使用 type 命令来区分命令是内建的还是外部的。例如这两个得出的结果是不同的

    type exit type vim

    得到的是两种结果,若是对ls你还能得到第三种结果

    #得到这样的结果说明是内建命令,正如上文所说内建命令都是在 bash 源码中的 builtins 的.def中 xxx is a shell builtin #得到这样的结果说明是外部命令,正如上文所说,外部命令在/usr/bin or /usr/sbin等等中 xxx is /usr/bin/xxx #若是得到alias的结果,说明该指令为命令别名所设定的名称; xxx is an alias for xx --xxx

     

     

    1. help 命令

    本实验环境是 zsh,而 zsh 中内置并没有 help 命令,我们可以进入 bash 中,在 bash 中内置有该命令

    bash

    做好了以上的准备,我们就可以愉快的使用 help 命令了,我们可以尝试下这个命令:

    help ls

    得到的结果如图所示,为什么是这样的结果?

    因为 help 命令是用于显示 shell 内建命令的简要帮助信息。帮助信息中显示有该命令的简要说明以及一些参数的使用以及说明,一定记住 help 命令只能用于显示内建命令的帮助信息,不然就会得到你刚刚得到的结果。

    那如果是外部命令怎么办,不能就这么抛弃它呀。其实外部命令基本上都有一个参数--help,这样就可以得到相应的帮助,看到你想要的东西了。试试下面这个命令是不是能看到你想要的东西了。

    ls --help

     

     

    2. man 命令

    你可以尝试下这个命令

    man ls

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

    是不是好用许多,当然也不代表 help 就没有存在的必要,当你非常紧急只是忘记该用哪个参数的时候,help 这种显示简单扼要的信息就特别实用,若是不太紧急的时候就可以用 man 这种详细描述的查询方式

    在尝试上面这个命令时我们会发现最左上角显示“ LS (1)”,在这里,“ LS ”表示手册名称,而“(1)”表示该手册位于第一章节。这个章节又是什么?在 man 手册中一共有这么几个章节

    章节数

    说明

    1

    Standard commands (标准命令)

    2

    System calls (系统调用)

    3

    Library functions (库函数)

    4

    Special devices (设备说明)

    5

    File formats (文件格式)

    6

    Games and toys (游戏和娱乐)

    7

    Miscellaneous (杂项)

    8

    Administrative Commands (管理员命令)

    9

    其他(Linux特定的), 用来存放内核例行程序的文档。

    打开手册之后我们可以通过 pgup 与 pgdn 或者上下键来上下翻看,可以按 q 退出当前页面

     

     

    3. info 命令

    要是你觉得man显示的信息都还不够,满足不了你的需求,那试试 info 命令,注意实验楼的环境中没有安装 info,可以手动安装,安装和操作步骤如下:

    # 安装 info $ sudo apt-get update $ sudo apt-get install info # 查看 ls 命令的 info $ info ls

    得到的信息是不是比 man 还要多了,info 来自自由软件基金会的 GNU 项目,是 GNU 的超文本帮助系统,能够更完整的显示出 GNU 信息。所以得到的信息当然更多

    man 和 info 就像两个集合,它们有一个交集部分,但与 man 相比,info 工具可显示更完整的 GNU 工具信息。若 man 页包含的某个工具的概要信息在 info 中也有介绍,那么 man 页中会有“请参考 info 页更详细内容”的字样。

     

    2.1 crontab 简介

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

    通过 crontab 命令,我们可以在固定的间隔时间执行指定的系统指令或 shell script 脚本。时间间隔的单位可以是分钟、小时、日、月、周的任意组合。

    这里我们看一看crontab 的格式

    # Example of job definition: # .---------------- minute (0 - 59) # | .------------- hour (0 - 23) # | | .---------- day of month (1 - 31) # | | | .------- month (1 - 12) OR jan,feb,mar,apr ... # | | | | .---- day of week (0 - 6) (Sunday=0 or 7) OR sun,mon,tue,wed,thu,fri,sat # | | | | | # * * * * * user-name command to be executed

     

     

     

     

    2.2 crontab 准备

    crontab 在本实验环境中需要做一些特殊的准备,首先我们会启动 rsyslog,以便我们可以通过日志中的信息来了解我们的任务是否真正的被执行了(在本实验环境中需要手动启动,而在自己本地中 Ubuntu 会默认自行启动不需要手动启动)

    sudo apt-get install -y rsyslog sudo service rsyslog start

    在本实验环境中 crontab 也是不被默认启动的,同时不能在后台由 upstart 来管理,所以需要我们来启动它:

    sudo cron -f &

     

     

     

    2.2 crontab 准备

    crontab 在本实验环境中需要做一些特殊的准备,首先我们会启动 rsyslog,以便我们可以通过日志中的信息来了解我们的任务是否真正的被执行了(在本实验环境中需要手动启动,而在自己本地中 Ubuntu 会默认自行启动不需要手动启动)

    sudo apt-get install -y rsyslog sudo service rsyslog start

    在本实验环境中 crontab 也是不被默认启动的,同时不能在后台由 upstart 来管理,所以需要我们来启动它:

    sudo cron -f &

     

     

    2.3 crontab 使用

    下面将开始 crontab 的使用了,我们通过下面一个命令来添加一个计划任务

    crontab -e

    第一次启动会出现这样一个画面,这是让我们选择编辑的工具,选择第二个基本的 vim 就可以了

    而选择后我们会进入这样一个画面,这就是添加计划的地方了,与一般的配置文档相同,以#号开头的都是注释,通过文档的最后一排我们可以猜猜 crontab 的格式是什么样的呢?

    详细的格式可以使用上一节中学习到的 man 命令查看:

    man crontab

    在了解命令格式之后,我们通过这样的一个例子来完成一个任务的添加,在文档的最后一排加上这样一排命令,该任务是每分钟我们会在/home/shiyanlou目录下创建一个以当前的年月日时分秒为名字的空白文件

    */1 * * * * touch /home/shiyanlou/$(date +\%Y\%m\%d\%H\%M\%S)

    注意 “ % ” 在 crontab 文件中,有结束命令行、换行、重定向的作用,前面加 ” \ ” 符号转义,否则,“ % ” 符号将执行其结束命令行或者换行的作用,并且其后的内容会被做为标准输入发送给前面的命令。

    添加成功后我们会得到最后一排 installing new crontab 的一个提示

    当然我们也可以通过这样的一个指令来查看我们添加了哪些任务

    crontab -l

    通过图中的显示,我们也可以看出,我们正确的保存并且添加成功了该任务的

    虽然我们添加了任务,但是如果 cron 的守护进程并没有启动,它根本都不会监测到有任务,当然也就不会帮我们执行,我们可以通过以下2种方式来确定我们的 cron 是否成功的在后台启动,默默的帮我们做事,若是没有就得执行上文准备中的第二步了

    ps aux | grep cron or pgrep cron

    通过下图可以看到任务在创建之后,执行了几次,生成了一些文件,且每分钟生成一个:

    我们通过这样一个命令可以查看到执行任务命令之后在日志中的信息反馈

    sudo tail -f /var/log/syslog

    从图中我们可以看到分别在13点28、29、30分的01秒为我们在 shiyanlou 用户的家目录下创建了文件

    当我们并不需要这个任务的时候我们可以使用这么一个命令去删除任务

    crontab -r

    通过图中我们可以看出我们删除之后再查看任务列表,系统已经显示该用户并没有任务哦

     

     

     

    三、crontab 的深入

    每个用户使用 crontab -e 添加计划任务,都会在 /var/spool/cron/crontabs 中添加一个该用户自己的任务文档,这样目的是为了隔离。

    如果是系统级别的定时任务,应该如何处理?只需要以 sudo 权限编辑 /etc/crontab 文件就可以。

    cron 服务监测时间最小单位是分钟,所以 cron 会每分钟去读取一次 /etc/crontab 与 /var/spool/cron/crontabs 里面的內容。

    在 /etc 目录下,cron 相关的目录有下面几个:

    每个目录的作用:

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

    系统默认执行时间可以根据需求进行修改。

     

     

    挑战:备份日志

    小明是一个服务器管理员,他需要每天备份论坛数据(这里我们用 alternatives.log 日志替代),备份当天的日志并删除之前的日志。而且备份之后文件名是 年-月-日 的格式。alternatives.log 在 /var/log/ 下面。

    目标

    1. 为 shiyanlou 用户添加计划任务
    2. 每天凌晨 3 点的时候定时备份 alternatives.log 到 /home/shiyanlou/tmp/ 目录
    3. 命名格式为 年-月-日,比如今天是2017年4月1日,那么文件名为 2017-04-01

    提示语

    • date
    • crontab
    • cp 命令
    • 用一条命令写在 crontab 里面即可,不用写脚本

    注意 crontab 的计划任务设定的用户:

    $ crontab -e 表示为当前用户添加计划任务 $ sudo crontab -e 表示为root用户添加计划任务

    注意使用下面的命令启动 crontab:

    $ sudo cron -f &

    参考答案

    注意:请务必自己独立思考解决问题之后再对照参考答案,一开始直接看参考答案收获不大。

    sudo cron -f & crontab -e 添加 0 3 * * * sudo rm /home/shiyanlou/tmp/* 0 3 * * * sudo cp /var/log/alternatives.log /home/shiyanlou/tmp/$(date +\%Y-\%m-\%d)

     

     

     

    2.1 顺序执行多条命令

    当我们需要使用apt-get安装一个软件,然后安装完成后立即运行安装的软件(或命令工具),又恰巧你的主机才更换的软件源还没有更新软件列表(比如之前我们的环境中,每次重新开始实验就得sudo apt-get update,现在已经没有这个问题了),那么你可能会有如下一系列操作:

    $ sudo apt-get update # 等待——————————然后输入下面的命令 $ sudo apt-get install some-tool //这里some-tool是指具体的软件包,例如:banner # 等待——————————然后输入下面的命令 $ some-tool

    这时你可能就会想:要是我可以一次性输入完,让它自己去依次执行各命令就好了,这就是我们这一小节要解决的问题。

    简单的顺序执行你可以使用;来完成,比如上述操作你可以:

    $ sudo apt-get update;sudo apt-get install some-tool;some-tool # 让它自己运行

     

     

    2.2 有选择的执行命令

    关于上面的操作,不知你有没有思考过一个问题,如果我们在让它自动顺序执行命令时,前面的命令执行不成功,而后面的命令又依赖于上一条命令的结果,那么就会造成花了时间,最终却得到一个错误的结果,而且有时候直观的看你还无法判断结果是否正确。那么我们需要能够有选择性的来执行命令,比如上一条命令执行成功才继续下一条,或者不成功又该做出其它什么处理,比如我们使用which来查找是否安装某个命令,如果找到就执行该命令,否则什么也不做(虽然这个操作没有什么实际意义,但可帮你更好的理解一些概念):

    $ which cowsay>/dev/null && cowsay -f head-in ohch~

    你如果没有安装cowsay,你可以先执行一次上述命令,你会发现什么也没发生,你再安装好之后你再执行一次上述命令,你也会发现一些惊喜。

    上面的&&就是用来实现选择性执行的,它表示如果前面的命令执行结果(不是表示终端输出的内容,而是表示命令执行状态的结果)返回0则执行后面的,否则不执行,你可以从$?环境变量获取上一次命令的返回结果:

    学习过 C 语言的用户应该知道在 C 语言里面&&表示逻辑与,而且还有一个||表示逻辑或,同样 Shell 也有一个||,它们的区别就在于,shell中的这两个符号除了也可用于表示逻辑与和或之外,就是可以实现这里的命令执行顺序的简单控制。||在这里就是与&&相反的控制效果,当上一条命令执行结果为≠0($?≠0)时则执行它后面的命令:

    $ 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"

    我画个流程图来解释一下上面的流程:

     

     

     

    三、管道

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

    管道又分为匿名管道和具名管道(这里将不会讨论在源程序中使用系统调用创建并使用管道的情况,它与命令行的管道在内核中实际都是采用相同的机制)。我们在使用一些过滤程序时经常会用到的就是匿名管道,在命令行中由|分隔符表示,|在前面的内容中我们已经多次使用到了。具名管道简单的说就是有名字的管道,通常只会在源程序中用到具名管道。下面我们就将通过一些常用的可以使用管道的"过滤程序"来帮助你熟练管道的使用。

     

    3.1 试用

    先试用一下管道,比如查看/etc目录下有哪些文件和目录,使用ls命令来查看:

    $ ls -al /etc

    有太多内容,屏幕不能完全显示,这时候可以使用滚动条或快捷键滚动窗口来查看。不过这时候可以使用管道:

    $ ls -al /etc | less

    通过管道将前一个命令(ls)的输出作为下一个命令(less)的输入,然后就可以一行一行地看。

     

     

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

    打印/etc/passwd文件中以:为分隔符的第1个字段和第6个字段分别表示用户名和其家目录:

    $ cut /etc/passwd -d ':' -f 1,6

    打印/etc/passwd文件中每一行的前N个字符:

    # 前五个(包含第五个) $ cut /etc/passwd -c -5 # 前五个之后的(包含第五个) $ cut /etc/passwd -c 5- # 第五个 $ cut /etc/passwd -c 5 # 2到5之间的(包含第五个) $ cut /etc/passwd -c 2-5

     

     

     

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

    grep命令是很强大的,也是相当常用的一个命令,它结合正则表达式可以实现很复杂却很高效的匹配和查找,不过在学习正则表达式之前,这里介绍它简单的使用,而关于正则表达式后面将会有单独一小节介绍到时会再继续学习grep命令和其他一些命令。

    grep命令的一般形式为:

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

    还是先体验一下,我们搜索/home/shiyanlou目录下所有包含"shiyanlou"的文本文件,并显示出现在文本中的行号:

    $ grep -rnI "shiyanlou" ~

    -r 参数表示递归搜索子目录中的文件,-n表示打印匹配项行号,-I表示忽略二进制文件。这个操作实际没有多大意义,但可以感受到grep命令的强大与实用。

    当然也可以在匹配字段中使用正则表达式,下面简单的演示:

    # 查看环境变量中以"yanlou"结尾的字符串 $ export | grep ".*yanlou$"

    其中$就表示一行的末尾。

     

     

    3.4 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

    注意:对于西文字符来说,一个字符就是一个字节,但对于中文字符一个汉字是大于2个字节的,具体数目是由字符编码决定的

    再来结合管道来操作一下,下面统计 /etc 下面所有目录数:

    $ ls -dl /etc/*/ | wc -l

     

    3.5 sort 排序命令

    这个命令前面我们也是用过多次,功能很简单就是将输入按照一定方式排序,然后再输出,它支持的排序有按字典排序,数字排序,按月份排序,随机排序,反转排序,指定特定字段进行排序等等。

    默认为字典排序:

    $ cat /etc/passwd | sort

    反转排序:

    $ cat /etc/passwd | sort -r

    按特定字段排序:

    $ cat /etc/passwd | sort -t':' -k 3

    上面的-t参数用于指定字段的分隔符,这里是以":"作为分隔符;-k 字段号用于指定对哪一个字段进行排序。这里/etc/passwd文件的第三个字段为数字,默认情况下是以字典序排序的,如果要按照数字排序就要加上-n参数:

    $ cat /etc/passwd | sort -t':' -k 3 -n

    注意观察第二个冒号后的数字: 

     

     

     

    3.6 uniq 去重命令

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

    • 过滤重复行

    我们可以使用history命令查看最近执行过的命令(实际为读取${SHELL}_history文件,如我们环境中的~/.zsh_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 -u

    这就是 Linux/UNIX 哲学吸引人的地方,大繁至简,一个命令只干一件事却能干到最好。

    • 输出重复行

    # 输出重复过的行(重复的只输出一个)及重复次数 $ history | cut -c 8- | cut -d ' ' -f 1 | sort | uniq -dc # 输出所有重复的行 $ history | cut -c 8- | cut -d ' ' -f 1 | sort | uniq -D

    文本处理命令还有很多,下一节将继续介绍一些常用的文本处理的命令。

    轻松一下

    使用以前介绍过的方法,安装aview和imagemagick,然后用asciiview命令显示图片,使用方法可以用 man 命令查看。

    Linus大神的照片地址 http://labfile.oss.aliyuncs.com/courses/1/Linus.png

    执行以下命令安装工具包并下载图片:

    shiyanlou:~/ $ sudo apt update shiyanlou:~/ $ sudo apt install -y aview imagemagick shiyanlou:~/ $ wget http://labfile.oss.aliyuncs.com/courses/1/Linus.png

    执行 asciiview [图片文件名] 即可打开图片:

     

     

    2.1 tr 命令

    tr 命令可以用来删除一段文本信息中的某些文字。或者将其进行转换。

    使用方式:

    tr [option]...SET1 [SET2]

    常用的选项有:

    选项

    说明

    -d

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

    -s

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

    操作举例:

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

    更多 tr 的使用,你可以使用--help或者man tr获得。

     

     

    col 命令可以将Tab换成对等数量的空格键,或反转这个操作。

    使用方式:

    col [option]

    常用的选项有:

    选项

    说明

    -x

    将Tab转换为空格

    -h

    将空格转换为Tab(默认选项)

    操作举例:

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

     

     

     

     

    2.3 join命令

    学过数据库的用户对这个应该不会陌生,这个命令就是用于将两个文件中包含相同内容的那一行合并在一起。

    使用方式:

    join [option]... file1 file2

    常用的选项有:

    选项

    说明

    -t

    指定分隔符,默认为空格

    -i

    忽略大小写的差异

    -1

    指明第一个文件要用哪个字段来对比,默认对比第一个字段

    -2

    指明第二个文件要用哪个字段来对比,默认对比第一个字段

    操作举例:

    $ cd /home/shiyanlou # 创建两个文件 $ echo '1 hello' > file1 $ echo '1 shiyanlou' > file2 $ join file1 file2 # 将/etc/passwd与/etc/shadow两个文件合并,指定以':'作为分隔符 $ sudo join -t':' /etc/passwd /etc/shadow # 将/etc/passwd与/etc/group两个文件合并,指定以':'作为分隔符, 分别比对第4和第3个字段 $ sudo join -t':' -1 4 /etc/passwd -2 3 /etc/group

     

     

     

    2.4 paste命令

    paste这个命令与join 命令类似,它是在不对比数据的情况下,简单地将多个文件合并一起,以Tab隔开。

    使用方式:

    paste [option] file...

    常用的选项有:

    选项

    说明

    -d

    指定合并的分隔符,默认为Tab

    -s

    不合并到一行,每个文件为一行

    操作举例:

    $ echo hello > file1 $ echo shiyanlou > file2 $ echo www.shiyanlou.com > file3 $ paste -d ':' file1 file2 file3 $ paste -s file1 file2 file3

     

     

    1.1 实验内容

    你可能对重定向这个概念感到些许陌生,但你应该在前面的课程中多次见过>或>>操作了,并知道他们分别是将标准输出导向一个文件或追加到一个文件中。这其实就是重定向,将原本输出到标准输出的数据重定向到一个文件中,因为标准输出(/dev/stdout)本身也是一个文件,我们将命令输出导向另一个文件自然也是没有任何问题的。

    1.2 实验知识点

    • 重定向怎么用
    • 文件描述符(0,1,2)

     

    二、数据流重定向

    下面我们简单的回顾一下我们前面经常用到的两个重定向操作:

    $ echo 'hello shiyanlou' > redirect $ echo 'www.shiyanlou.com' >> redirect $ cat redirect

    当然前面没有用到的<和<<操作也是没有问题的,如你理解的一样,它们的区别在于重定向的方向不一致而已,>表示是从左到右,<右到左。

     

     

    2.1 简单的重定向

    在更多了解 Linux 的重定向之前,我们需要先知道一些基本的东西,前面我们已经提到过 Linux 默认提供了三个特殊设备,用于终端的显示和输出,分别为stdin(标准输入,对应于你在终端的输入),stdout(标准输出,对应于终端的输出),stderr(标准错误输出,对应于终端的输出)。

    文件描述符

    设备文件

    说明

    0

    /dev/stdin

    标准输入

    1

    /dev/stdout

    标准输出

    2

    /dev/stderr

    标准错误

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

    我们可以这样使用这些文件描述符:

    默认使用终端的标准输入作为命令的输入和标准输出作为命令的输出

    $ cat (按Ctrl+C退出)

    将cat的连续输出(heredoc方式)重定向到一个文件

    $ mkdir Documents $ cat > Documents/test.c <<EOF #include <stdio.h> int main() { printf("hello world\n"); return 0; } EOF

    将一个文件作为命令的输入,标准输出作为命令的输出

    $ cat Documents/test.c

    将echo命令通过管道传过来的数据作为cat命令的输入,将标准输出作为命令的输出

    $ echo 'hi' | cat

    将echo命令的输出从默认的标准输出重定向到一个普通文件

    $ echo 'hello shiyanlou' > redirect $ cat redirect

    初学者这里要注意不要将管道和重定向混淆,管道默认是连接前一个命令的输出到下一个命令的输入,而重定向通常是需要一个文件来建立两个命令的连接,你可以仔细体会一下上述第三个操作和最后两个操作的异同点。

     

     

     

    2.2 标准错误重定向

    重定向标准输出到文件,这是一个很实用的操作,另一个很实用的操作是将标准错误重定向,标准输出和标准错误都被指向伪终端的屏幕显示,所以我们经常看到的一个命令的输出通常是同时包含了标准输出和标准错误的结果的。比如下面的操作:

    # 使用cat 命令同时读取两个文件,其中一个存在,另一个不存在 $ cat Documents/test.c hello.c # 你可以看到除了正确输出了前一个文件的内容,还在末尾出现了一条错误信息 # 下面我们将输出重定向到一个文件 $ cat Documents/test.c hello.c > somefile

    遗憾的是,这里依然出现了那条错误信息,这正是因为如我上面说的那样,标准输出和标准错误虽然都指向终端屏幕,实际它们并不一样。那有的时候我们就是要隐藏某些错误或者警告,那又该怎么做呢。这就需要用到我们前面讲的文件描述符了:

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

    注意你应该在输出重定向文件描述符前加上&,否则shell会当做重定向到一个文件名为1的文件中

     

     

     

    2.2 标准错误重定向

    重定向标准输出到文件,这是一个很实用的操作,另一个很实用的操作是将标准错误重定向,标准输出和标准错误都被指向伪终端的屏幕显示,所以我们经常看到的一个命令的输出通常是同时包含了标准输出和标准错误的结果的。比如下面的操作:

    # 使用cat 命令同时读取两个文件,其中一个存在,另一个不存在 $ cat Documents/test.c hello.c # 你可以看到除了正确输出了前一个文件的内容,还在末尾出现了一条错误信息 # 下面我们将输出重定向到一个文件 $ cat Documents/test.c hello.c > somefile

    遗憾的是,这里依然出现了那条错误信息,这正是因为如我上面说的那样,标准输出和标准错误虽然都指向终端屏幕,实际它们并不一样。那有的时候我们就是要隐藏某些错误或者警告,那又该怎么做呢。这就需要用到我们前面讲的文件描述符了:

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

    注意你应该在输出重定向文件描述符前加上&,否则shell会当做重定向到一个文件名为1的文件中

     

     

     

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

    你可能还有这样的需求,除了需要将输出重定向到文件,也需要将信息打印在终端。那么你可以使用tee命令来实现:

    $ echo 'hello shiyanlou' | tee hello

     

     

    2.4 永久重定向

    你应该可以看出我们前面的重定向操作都只是临时性的,即只对当前命令有效,那如何做到“永久”有效呢,比如在一个脚本中,你需要某一部分的命令的输出全部进行重定向,难道要让你在每个命令上面加上临时重定向的操作嘛,当然不需要,我们可以使用exec命令实现“永久”重定向。exec命令的作用是使用指定的命令替换当前的 Shell,即使用一个进程替换当前进程,或者指定新的重定向:

    # 先开启一个子 Shell $ zsh # 使用exec替换当前进程的重定向,将标准输出重定向到一个文件 $ exec 1>somefile # 后面你执行的命令的输出都将被重定向到文件中,直到你退出当前子shell,或取消exec的重定向(后面将告诉你怎么做) $ ls $ exit $ cat somefile

     

     

    2.5 创建输出文件描述符

    在 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

     

     

    2.6 关闭文件描述符

    如上面我们打开的3号文件描述符,可以使用如下操作将它关闭:

    $ exec 3>&- $ cd /dev/fd;ls -Al;cd -

     

     

    2.7 完全屏蔽命令的输出

    在 Linux 中有一个被称为“黑洞”的设备文件,所有导入它的数据都将被“吞噬”。

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

    我们可以利用设个/dev/null屏蔽命令的输出:

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

    上面这样的操作将使你得不到任何输出结果。

     

     

    2.8 使用 xargs 分割参数列表

    xargs 是一条 UNIX 和类 UNIX 操作系统的常用命令。它的作用是将参数列表转换成小块分段传递给其他命令,以避免参数列表过长的问题。

    这个命令在有些时候十分有用,特别是当用来处理产生大量输出结果的命令如 find,locate 和 grep 的结果,详细用法请参看 man 文档。

    $ cut -d: -f1 < /etc/passwd | sort | xargs echo

    上面这个命令用于将/etc/passwd文件按:分割取第一个字段排序后,使用echo命令生成一个列表。

    轻松一下

    之前介绍过一个在命令行将图片转换为 ascii 字符查看的工具 aview/asciiview,不过它是黑白的。现在,这里是个彩色的:

    $ sudo apt-get install caca-utils $ cacaview <pic_file> $ cacademo $ cacafire

     

     

    挑战:历史命令

    介绍

    在 Linux 中,对于文本的处理和分析是极为重要的,现在有一个文件叫做 data1,可以使用下面的命令下载:

    $ cd /home/shiyanlou $ wget http://labfile.oss.aliyuncs.com/courses/1/data1

    data1 文件里记录是一些命令的操作记录,现在需要你从里面找出出现频率次数前3的命令并保存在 /home/shiyanlou/result。

    目标

    1. 处理文本文件 /home/shiyanlou/data1
    2. 将结果写入 /home/shiyanlou/result
    3. 结果包含三行内容,每行内容都是出现的次数和命令名称,如“100 ls”

    提示

    1. cut 截取 (参数可以使用 -c 8-,使用 man cut 可以查看含义)
    2. uniq -dc 去重
    3. sort 的参数选择 -k1 -n -r
    4. 操作过程使用管道,例如:

    $ cd /home/shiyanlou $ cat data1 |....|....|.... > /home/shiyanlou/result

    来源

    2016 年百度校招面试题

    参考答案

    注意:请务必自己独立思考解决问题之后再对照参考答案,一开始直接看参考答案收获不大。

    cat data1 |cut -c 8-|sort|uniq -dc|sort -rn -k1 |head -3 > /home/shiyanlou/result

     

     

    二、正则表达式

    什么是正则表达式呢?

    正则表达式,又称正规表示式、正规表示法、正规表达式、规则表达式、常规表示法(英语:Regular Expression,在代码中常简写为 regex、regexp 或 RE),计算机科学的一个概念。正则表达式使用单个字符串来描述、匹配一系列符合某个句法规则的字符串。在很多文本编辑器里,正则表达式通常被用来检索、替换那些符合某个模式的文本。

    许多程序设计语言都支持利用正则表达式进行字符串操作。例如,在 Perl 中就内建了一个功能强大的正则表达式引擎。正则表达式这个概念最初是由 UNIX 中的工具软件(例如sed和grep)普及开的。正则表达式通常缩写成“regex”,单数有 regexp、regex,复数有 regexps、regexes、regexen。

    简单的说形式和功能上正则表达式和我们前面讲的通配符很像,不过它们之间又有很大差别,特别在于一些特殊的匹配字符的含义上,希望初学者注意不要将两者弄混淆。

     

     

    2.2 基本语法

    一个正则表达式通常被称为一个模式(pattern),为用来描述或者匹配一系列符合某个句法规则的字符串。

    选择

    |竖直分隔符表示选择,例如"boy|girl"可以匹配"boy"或者"girl"

    数量限定

    数量限定除了我们举例用的*,还有+加号,?问号,如果在一个模式中不加数量限定符则表示出现一次且仅出现一次:

    • +表示前面的字符必须出现至少一次(1次或多次),例如,"goo+gle",可以匹配"gooogle","goooogle"等;
    • ?表示前面的字符最多出现一次(0次或1次),例如,"colou?r",可以匹配"color"或者"colour";
    • *星号代表前面的字符可以不出现,也可以出现一次或者多次(0次、或1次、或多次),例如,“0*42”可以匹配42、042、0042、00042等。

    范围和优先级

    ()圆括号可以用来定义模式字符串的范围和优先级,这可以简单的理解为是否将括号内的模式串作为一个整体。例如,"gr(a|e)y"等价于"gray|grey",(这里体现了优先级,竖直分隔符用于选择a或者e而不是gra和ey),"(grand)?father"匹配father和grandfather(这里体验了范围,?将圆括号内容作为一个整体匹配)。

    语法(部分)

    正则表达式有多种不同的风格,下面列举一些常用的作为 PCRE 子集的适用于perl和python编程语言及grep或egrep的正则表达式匹配规则:(由于markdown表格解析的问题,下面的竖直分隔符用全角字符代替,实际使用时请换回半角字符)

    PCRE(Perl Compatible Regular Expressions中文含义:perl语言兼容正则表达式)是一个用 C 语言编写的正则表达式函数库,由菲利普.海泽(Philip Hazel)编写。PCRE是一个轻量级的函数库,比Boost 之类的正则表达式库小得多。PCRE 十分易用,同时功能也很强大,性能超过了 POSIX 正则表达式库和一些经典的正则表达式库。

    字符

    描述

    \

    将下一个字符标记为一个特殊字符、或一个原义字符。例如,“n”匹配字符“n”。“\n”匹配一个换行符。序列“\\”匹配“\”而“\(”则匹配“(”。

    ^

    匹配输入字符串的开始位置。

    $

    匹配输入字符串的结束位置。

    {n}

    n是一个非负整数。匹配确定的n次。例如,“o{2}”不能匹配“Bob”中的“o”,但是能匹配“food”中的两个o。

    {n,}

    n是一个非负整数。至少匹配n次。例如,“o{2,}”不能匹配“Bob”中的“o”,但能匹配“foooood”中的所有o。“o{1,}”等价于“o+”。“o{0,}”则等价于“o*”。

    {n,m}

    m和n均为非负整数,其中n<=m。最少匹配n次且最多匹配m次。例如,“o{1,3}”将匹配“fooooood”中的前三个o。“o{0,1}”等价于“o?”。请注意在逗号和两个数之间不能有空格。

    *

    匹配前面的子表达式零次或多次。例如,zo*能匹配“z”、“zo”以及“zoo”。*等价于{0,}。

    +

    匹配前面的子表达式一次或多次。例如,“zo+”能匹配“zo”以及“zoo”,但不能匹配“z”。+等价于{1,}。

    ?

    匹配前面的子表达式零次或一次。例如,“do(es)?”可以匹配“do”或“does”中的“do”。?等价于{0,1}。

    ?

    当该字符紧跟在任何一个其他限制符(*,+,?,{n},{n,},{n,m})后面时,匹配模式是非贪婪的。非贪婪模式尽可能少的匹配所搜索的字符串,而默认的贪婪模式则尽可能多的匹配所搜索的字符串。例如,对于字符串“oooo”,“o+?”将匹配单个“o”,而“o+”将匹配所有“o”。

    .

    匹配除“\n”之外的任何单个字符。要匹配包括“\n”在内的任何字符,请使用像“(.|\n)”的模式。

    (pattern)

    匹配pattern并获取这一匹配的子字符串。该子字符串用于向后引用。要匹配圆括号字符,请使用“\(”或“\)”。

    x|y

    匹配x或y。例如,“z|food”能匹配“z”或“food”。“(z|f)ood”则匹配“zood”或“food”。

    [xyz]

    字符集合(character class)。匹配所包含的任意一个字符。例如,“[abc]”可以匹配“plain”中的“a”。其中特殊字符仅有反斜线\保持特殊含义,用于转义字符。其它特殊字符如星号、加号、各种括号等均作为普通字符。脱字符^如果出现在首位则表示负值字符集合;如果出现在字符串中间就仅作为普通字符。连字符 - 如果出现在字符串中间表示字符范围描述;如果出现在首位则仅作为普通字符。

    [^xyz]

    排除型(negate)字符集合。匹配未列出的任意字符。例如,“[^abc]”可以匹配“plain”中的“plin”。

    [a-z]

    字符范围。匹配指定范围内的任意字符。例如,“[a-z]”可以匹配“a”到“z”范围内的任意小写字母字符。

    [^a-z]

    排除型的字符范围。匹配任何不在指定范围内的任意字符。例如,“[^a-z]”可以匹配任何不在“a”到“z”范围内的任意字符。

    优先级

    优先级为从上到下从左到右,依次降低:

    运算符

    说明

    \

    转义符

    (), (?:), (?=), []

    括号和中括号

    *、+、?、{n}、{n,}、{n,m}

    限定符

    ^、$、\任何元字符

    定位点和序列

    选择

    更多正则表达式的内容可以参考以下链接:

    regex的思导图:

     

     

    三、grep模式匹配命令

    上面空谈了那么多正则表达式的内容也并没有提及具体该如何使用它,实在枯燥,如果说正则表达式是一门武功,那它也只能算得上一些口诀招式罢了,要把它真正练起来还得需要一些兵器在手才行,这里我们要介绍的grep命令以及后面要讲的sed,awk这些就该算作是这样的兵器了。

     

     

     

    3.1 基本操作

    grep命令用于打印输出文本中匹配的模式串,它使用正则表达式作为模式匹配的条件。grep支持三种正则表达式引擎,分别用三个参数指定:

    参数

    说明

    -E

    POSIX扩展正则表达式,ERE

    -G

    POSIX基本正则表达式,BRE

    -P

    Perl正则表达式,PCRE

    不过在你没学过perl语言的大多数情况下你将只会使用到ERE和BRE,所以我们接下来的内容都不会讨论到PCRE中特有的一些正则表达式语法(它们之间大部分内容是存在交集的,所以你不用担心会遗漏多少重要内容)

    在通过grep命令使用正则表达式之前,先介绍一下它的常用参数:

    参数

    说明

    -b

    将二进制文件作为文本来进行匹配

    -c

    统计以模式匹配的数目

    -i

    忽略大小写

    -n

    显示匹配文本所在行的行号

    -v

    反选,输出不匹配行的内容

    -r

    递归匹配查找

    -A n

    n为正整数,表示after的意思,除了列出匹配行之外,还列出后面的n行

    -B n

    n为正整数,表示before的意思,除了列出匹配行之外,还列出前面的n行

    --color=auto

    将输出中的匹配项设置为自动颜色显示

    注:在大多数发行版中是默认设置了grep的颜色的,你可以通过参数指定或修改GREP_COLOR环境变量。

     

     

    3.2 使用正则表达式

    使用基本正则表达式,BRE

    • 位置

    查找/etc/group文件中以"shiyanlou"为开头的行

    $ grep 'shiyanlou' /etc/group $ grep '^shiyanlou' /etc/group

    • 数量

    # 将匹配以'z'开头以'o'结尾的所有字符串 $ echo 'zero\nzo\nzoo' | grep 'z.*o' # 将匹配以'z'开头以'o'结尾,中间包含一个任意字符的字符串 $ echo 'zero\nzo\nzoo' | grep 'z.o' # 将匹配以'z'开头,以任意多个'o'结尾的字符串 $ echo 'zero\nzo\nzoo' | grep 'zo*'

    注意:其中\n为换行符

    • 选择

    # grep默认是区分大小写的,这里将匹配所有的小写字母 $ echo '1234\nabcd' | grep '[a-z]' # 将匹配所有的数字 $ echo '1234\nabcd' | grep '[0-9]' # 将匹配所有的数字 $ echo '1234\nabcd' | grep '[[:digit:]]' # 将匹配所有的小写字母 $ echo '1234\nabcd' | grep '[[:lower:]]' # 将匹配所有的大写字母 $ echo '1234\nabcd' | grep '[[:upper:]]' # 将匹配所有的字母和数字,包括0-9,a-z,A-Z $ echo '1234\nabcd' | grep '[[:alnum:]]' # 将匹配所有的字母 $ echo '1234\nabcd' | grep '[[:alpha:]]'

    下面包含完整的特殊符号及说明:

    特殊符号

    说明

    [:alnum:]

    代表英文大小写字母及数字,亦即 0-9, A-Z, a-z

    [:alpha:]

    代表任何英文大小写字母,亦即 A-Z, a-z

    [:blank:]

    代表空白键与 [Tab] 按键两者

    [:cntrl:]

    代表键盘上面的控制按键,亦即包括 CR, LF, Tab, Del.. 等等

    [:digit:]

    代表数字而已,亦即 0-9

    [:graph:]

    除了空白字节 (空白键与 [Tab] 按键) 外的其他所有按键

    [:lower:]

    代表小写字母,亦即 a-z

    [:print:]

    代表任何可以被列印出来的字符

    [:punct:]

    代表标点符号 (punctuation symbol),亦即:" ' ? ! ; : # $...

    [:upper:]

    代表大写字母,亦即 A-Z

    [:space:]

    任何会产生空白的字符,包括空白键, [Tab], CR 等等

    [:xdigit:]

    代表 16 进位的数字类型,因此包括: 0-9, A-F, a-f 的数字与字节

    注意:之所以要使用特殊符号,是因为上面的[a-z]不是在所有情况下都管用,这还与主机当前的语系有关,即设置在LANG环境变量的值,zh_CN.UTF-8的话[a-z],即为所有小写字母,其它语系可能是大小写交替的如,"a A b B...z Z",[a-z]中就可能包含大写字母。所以在使用[a-z]时请确保当前语系的影响,使用[:lower:]则不会有这个问题。

    # 排除字符 $ $ echo 'geek\ngood' | grep '[^o]'

    注意:当^放到中括号内为排除字符,否则表示行首。

    使用扩展正则表达式,ERE

    要通过grep使用扩展正则表达式需要加上-E参数,或使用egrep。

    • 数量

    # 只匹配"zo" $ echo 'zero\nzo\nzoo' | grep -E 'zo{1}' # 匹配以"zo"开头的所有单词 $ echo 'zero\nzo\nzoo' | grep -E 'zo{1,}'

    注意:推荐掌握{n,m}即可,+,?,*,这几个不太直观,且容易弄混淆。

    • 选择

    # 匹配"www.shiyanlou.com"和"www.google.com" $ echo 'www.shiyanlou.com\nwww.baidu.com\nwww.google.com' | grep -E 'www\.(shiyanlou|google)\.com' # 或者匹配不包含"baidu"的内容 $ echo 'www.shiyanlou.com\nwww.baidu.com\nwww.google.com' | grep -Ev 'www\.baidu\.com'

    注意:因为.号有特殊含义,所以需要转义。

    关于正则表达式和grep命令的内容就介绍这么多,下面会介绍两个更强大的工具sed和awk,但同样也正是因为这两个工具的强大,我们的内容无法包含它们的全部,这里将只对基本内容作介绍。

     

     

    3.2 使用正则表达式

    使用基本正则表达式,BRE

    • 位置

    查找/etc/group文件中以"shiyanlou"为开头的行

    $ grep 'shiyanlou' /etc/group $ grep '^shiyanlou' /etc/group

    • 数量

    # 将匹配以'z'开头以'o'结尾的所有字符串 $ echo 'zero\nzo\nzoo' | grep 'z.*o' # 将匹配以'z'开头以'o'结尾,中间包含一个任意字符的字符串 $ echo 'zero\nzo\nzoo' | grep 'z.o' # 将匹配以'z'开头,以任意多个'o'结尾的字符串 $ echo 'zero\nzo\nzoo' | grep 'zo*'

    注意:其中\n为换行符

    • 选择

    # grep默认是区分大小写的,这里将匹配所有的小写字母 $ echo '1234\nabcd' | grep '[a-z]' # 将匹配所有的数字 $ echo '1234\nabcd' | grep '[0-9]' # 将匹配所有的数字 $ echo '1234\nabcd' | grep '[[:digit:]]' # 将匹配所有的小写字母 $ echo '1234\nabcd' | grep '[[:lower:]]' # 将匹配所有的大写字母 $ echo '1234\nabcd' | grep '[[:upper:]]' # 将匹配所有的字母和数字,包括0-9,a-z,A-Z $ echo '1234\nabcd' | grep '[[:alnum:]]' # 将匹配所有的字母 $ echo '1234\nabcd' | grep '[[:alpha:]]'

    下面包含完整的特殊符号及说明:

    特殊符号

    说明

    [:alnum:]

    代表英文大小写字母及数字,亦即 0-9, A-Z, a-z

    [:alpha:]

    代表任何英文大小写字母,亦即 A-Z, a-z

    [:blank:]

    代表空白键与 [Tab] 按键两者

    [:cntrl:]

    代表键盘上面的控制按键,亦即包括 CR, LF, Tab, Del.. 等等

    [:digit:]

    代表数字而已,亦即 0-9

    [:graph:]

    除了空白字节 (空白键与 [Tab] 按键) 外的其他所有按键

    [:lower:]

    代表小写字母,亦即 a-z

    [:print:]

    代表任何可以被列印出来的字符

    [:punct:]

    代表标点符号 (punctuation symbol),亦即:" ' ? ! ; : # $...

    [:upper:]

    代表大写字母,亦即 A-Z

    [:space:]

    任何会产生空白的字符,包括空白键, [Tab], CR 等等

    [:xdigit:]

    代表 16 进位的数字类型,因此包括: 0-9, A-F, a-f 的数字与字节

    注意:之所以要使用特殊符号,是因为上面的[a-z]不是在所有情况下都管用,这还与主机当前的语系有关,即设置在LANG环境变量的值,zh_CN.UTF-8的话[a-z],即为所有小写字母,其它语系可能是大小写交替的如,"a A b B...z Z",[a-z]中就可能包含大写字母。所以在使用[a-z]时请确保当前语系的影响,使用[:lower:]则不会有这个问题。

    # 排除字符 $ $ echo 'geek\ngood' | grep '[^o]'

    注意:当^放到中括号内为排除字符,否则表示行首。

    使用扩展正则表达式,ERE

    要通过grep使用扩展正则表达式需要加上-E参数,或使用egrep。

    • 数量

    # 只匹配"zo" $ echo 'zero\nzo\nzoo' | grep -E 'zo{1}' # 匹配以"zo"开头的所有单词 $ echo 'zero\nzo\nzoo' | grep -E 'zo{1,}'

    注意:推荐掌握{n,m}即可,+,?,*,这几个不太直观,且容易弄混淆。

    • 选择

    # 匹配"www.shiyanlou.com"和"www.google.com" $ echo 'www.shiyanlou.com\nwww.baidu.com\nwww.google.com' | grep -E 'www\.(shiyanlou|google)\.com' # 或者匹配不包含"baidu"的内容 $ echo 'www.shiyanlou.com\nwww.baidu.com\nwww.google.com' | grep -Ev 'www\.baidu\.com'

    注意:因为.号有特殊含义,所以需要转义。

    关于正则表达式和grep命令的内容就介绍这么多,下面会介绍两个更强大的工具sed和awk,但同样也正是因为这两个工具的强大,我们的内容无法包含它们的全部,这里将只对基本内容作介绍。

     

    3.2 使用正则表达式

    使用基本正则表达式,BRE

    • 位置

    查找/etc/group文件中以"shiyanlou"为开头的行

    $ grep 'shiyanlou' /etc/group $ grep '^shiyanlou' /etc/group

    • 数量

    # 将匹配以'z'开头以'o'结尾的所有字符串 $ echo 'zero\nzo\nzoo' | grep 'z.*o' # 将匹配以'z'开头以'o'结尾,中间包含一个任意字符的字符串 $ echo 'zero\nzo\nzoo' | grep 'z.o' # 将匹配以'z'开头,以任意多个'o'结尾的字符串 $ echo 'zero\nzo\nzoo' | grep 'zo*'

    注意:其中\n为换行符

    • 选择

    # grep默认是区分大小写的,这里将匹配所有的小写字母 $ echo '1234\nabcd' | grep '[a-z]' # 将匹配所有的数字 $ echo '1234\nabcd' | grep '[0-9]' # 将匹配所有的数字 $ echo '1234\nabcd' | grep '[[:digit:]]' # 将匹配所有的小写字母 $ echo '1234\nabcd' | grep '[[:lower:]]' # 将匹配所有的大写字母 $ echo '1234\nabcd' | grep '[[:upper:]]' # 将匹配所有的字母和数字,包括0-9,a-z,A-Z $ echo '1234\nabcd' | grep '[[:alnum:]]' # 将匹配所有的字母 $ echo '1234\nabcd' | grep '[[:alpha:]]'

    下面包含完整的特殊符号及说明:

    特殊符号

    说明

    [:alnum:]

    代表英文大小写字母及数字,亦即 0-9, A-Z, a-z

    [:alpha:]

    代表任何英文大小写字母,亦即 A-Z, a-z

    [:blank:]

    代表空白键与 [Tab] 按键两者

    [:cntrl:]

    代表键盘上面的控制按键,亦即包括 CR, LF, Tab, Del.. 等等

    [:digit:]

    代表数字而已,亦即 0-9

    [:graph:]

    除了空白字节 (空白键与 [Tab] 按键) 外的其他所有按键

    [:lower:]

    代表小写字母,亦即 a-z

    [:print:]

    代表任何可以被列印出来的字符

    [:punct:]

    代表标点符号 (punctuation symbol),亦即:" ' ? ! ; : # $...

    [:upper:]

    代表大写字母,亦即 A-Z

    [:space:]

    任何会产生空白的字符,包括空白键, [Tab], CR 等等

    [:xdigit:]

    代表 16 进位的数字类型,因此包括: 0-9, A-F, a-f 的数字与字节

    注意:之所以要使用特殊符号,是因为上面的[a-z]不是在所有情况下都管用,这还与主机当前的语系有关,即设置在LANG环境变量的值,zh_CN.UTF-8的话[a-z],即为所有小写字母,其它语系可能是大小写交替的如,"a A b B...z Z",[a-z]中就可能包含大写字母。所以在使用[a-z]时请确保当前语系的影响,使用[:lower:]则不会有这个问题。

    # 排除字符 $ $ echo 'geek\ngood' | grep '[^o]'

    注意:当^放到中括号内为排除字符,否则表示行首。

    使用扩展正则表达式,ERE

    要通过grep使用扩展正则表达式需要加上-E参数,或使用egrep。

    • 数量

    # 只匹配"zo" $ echo 'zero\nzo\nzoo' | grep -E 'zo{1}' # 匹配以"zo"开头的所有单词 $ echo 'zero\nzo\nzoo' | grep -E 'zo{1,}'

    注意:推荐掌握{n,m}即可,+,?,*,这几个不太直观,且容易弄混淆。

    • 选择

    # 匹配"www.shiyanlou.com"和"www.google.com" $ echo 'www.shiyanlou.com\nwww.baidu.com\nwww.google.com' | grep -E 'www\.(shiyanlou|google)\.com' # 或者匹配不包含"baidu"的内容 $ echo 'www.shiyanlou.com\nwww.baidu.com\nwww.google.com' | grep -Ev 'www\.baidu\.com'

    注意:因为.号有特殊含义,所以需要转义。

    关于正则表达式和grep命令的内容就介绍这么多,下面会介绍两个更强大的工具sed和awk,但同样也正是因为这两个工具的强大,我们的内容无法包含它们的全部,这里将只对基本内容作介绍。

     

    4.2 sed编辑器的执行命令(这里”执行“解释为名词)

    sed执行命令格式:

    [n1][,n2]command [n1][~step]command # 其中一些命令可以在后面加上作用范围,形如: $ sed -i 's/sad/happy/g' test # g表示全局范围 $ sed -i 's/sad/happy/4' test # 4表示指定行中的第四个匹配字符串

    其中n1,n2表示输入内容的行号,它们之间为,逗号则表示从n1到n2行,如果为~波浪号则表示从n1开始以step为步进的所有行;command为执行动作,下面为一些常用动作指令:

    命令

    说明

    s

    行内替换

    c

    整行替换

    a

    插入到指定行的后面

    i

    插入到指定行的前面

    p

    打印指定行,通常与-n参数配合使用

    d

    删除指定行

     

     

     

    4.3 sed操作举例

    我们先找一个用于练习的文本文件:

    $ cp /etc/passwd ~

    打印指定行

    # 打印2-5行 $ nl passwd | sed -n '2,5p' # 打印奇数行 $ nl passwd | sed -n '1~2p'

    行内替换

    # 将输入文本中"shiyanlou" 全局替换为"hehe",并只打印替换的那一行,注意这里不能省略最后的"p"命令 $ sed -n 's/shiyanlou/hehe/gp' passwd

    注意: 行内替换可以结合正则表达式使用。

    行间替换

    $ nl passwd | grep "shiyanlou" # 删除第21行 $ sed -n '21c\www.shiyanlou.com' passwd (这里我们只把要删的行打印出来了,并没有真正的删除,如果要删除的话,请使用-i参数)

    关于sed命令就介绍这么多,你如果希望了解更多sed的高级用法,你可以参看如下链接:

     

     

    五、awk文本处理语言

    看到上面的标题,你可能会感到惊异,难道我们这里要学习的是一门“语言”么,确切的说,我们是要在这里学习awk文本处理语言,只是我们并不会在这里学习到比较完整的关于awk的内容,还是因为前面的原因,它太强大了,它的应用无处不在,我们无法在这里以简短的文字描述面面俱到,如果你有目标成为一个 linux 系统管理员,确实想学好 awk,不用担心,实验楼会在之后陆续上线linux系统管理员的学习路径,里面会有单独的关于正则表达式,awk,sed等相关课程,敬请期待吧。下面的内容,我们就作为一个关于awk的入门体验章节吧,其中会介绍一些awk的常用操作。

     

    5.1 awk介绍

    AWK是一种优良的文本处理工具,Linux及Unix环境中现有的功能最强大的数据处理引擎之一.其名称得自于它的创始人Alfred Aho(阿尔佛雷德·艾侯)、Peter Jay Weinberger(彼得·温伯格)和Brian Wilson Kernighan(布莱恩·柯林汉)姓氏的首个字母.AWK程序设计语言,三位创建者已将它正式定义为“样式扫描和处理语言”。它允许您创建简短的程序,这些程序读取输入文件、为数据排序、处理数据、对输入执行计算以及生成报表,还有无数其他的功能。最简单地说,AWK是一种用于处理文本的编程语言工具。

    在大多数linux发行版上面,实际我们使用的是gawk(GNU awk,awk的GNU版本),在我们的环境中ubuntu上,默认提供的是mawk,不过我们通常可以直接使用awk命令(awk语言的解释器),因为系统已经为我们创建好了awk指向mawk的符号链接。

    $ ll /usr/bin/awk

    nawk: 在 20 世纪 80 年代中期,对 awk语言进行了更新,并不同程度地使用一种称为 nawk(new awk) 的增强版本对其进行了替换。许多系统中仍然存在着旧的awk 解释器,但通常将其安装为 oawk (old awk) 命令,而 nawk 解释器则安装为主要的 awk 命令,也可以使用 nawk 命令。Dr. Kernighan 仍然在对 nawk 进行维护,与 gawk 一样,它也是开放源代码的,并且可以免费获得; gawk: 是 GNU Project 的awk解释器的开放源代码实现。尽管早期的 GAWK 发行版是旧的 AWK 的替代程序,但不断地对其进行了更新,以包含 NAWK 的特性; mawk 也是awk编程语言的一种解释器,mawk遵循 POSIX 1003.2 (草案 11.3)定义的 AWK 语言,包含了一些没有在AWK 手册中提到的特色,同时 mawk 提供一小部分扩展,另外据说mawk是实现最快的awk

     

    5.2 awk的一些基础概念

    awk所有的操作都是基于pattern(模式)—action(动作)对来完成的,如下面的形式:

    $ pattern {action}

    你可以看到就如同很多编程语言一样,它将所有的动作操作用一对{}花括号包围起来。其中pattern通常是表示用于匹配输入的文本的“关系式”或“正则表达式”,action则是表示匹配后将执行的动作。在一个完整awk操作中,这两者可以只有其中一个,如果没有pattern则默认匹配输入的全部文本,如果没有action则默认为打印匹配内容到屏幕。

    awk处理文本的方式,是将文本分割成一些“字段”,然后再对这些字段进行处理,默认情况下,awk以空格作为一个字段的分割符,不过这不是固定的,你可以任意指定分隔符,下面将告诉你如何做到这一点。

    5.3 awk命令基本格式

    awk [-F fs] [-v var=value] [-f prog-file | 'program text'] [file...]

    其中-F参数用于预先指定前面提到的字段分隔符(还有其他指定字段的方式) ,-v用于预先为awk程序指定变量,-f参数用于指定awk命令要执行的程序文件,或者在不加-f参数的情况下直接将程序语句放在这里,最后为awk需要处理的文本输入,且可以同时输入多个文本文件。现在我们还是直接来具体体验一下吧。

     

    5.4 awk操作体验

    先用vim新建一个文本文档

    $ vim test

    包含如下内容:

    I like linux www.shiyanlou.com

    • 使用awk将文本内容打印到终端

    # "quote>" 不用输入 $ awk '{ > print > }' test # 或者写到一行 $ awk '{print}' test

    说明:在这个操作中我是省略了pattern,所以awk会默认匹配输入文本的全部内容,然后在"{}"花括号中执行动作,即print打印所有匹配项,这里是全部文本内容

    • 将test的第一行的每个字段单独显示为一行

    $ awk '{ > if(NR==1){ > print $1 "\n" $2 "\n" $3 > } else { > print} > }' test # 或者 $ awk '{ > if(NR==1){ > OFS="\n" > print $1, $2, $3 > } else { > print} > }' test

    说明:你首先应该注意的是,这里我使用了awk语言的分支选择语句if,它的使用和很多高级语言如C/C++语言基本一致,如果你有这些语言的基础,这里将很好理解。另一个你需要注意的是NR与OFS,这两个是awk内建的变量,NR表示当前读入的记录数,你可以简单的理解为当前处理的行数,OFS表示输出时的字段分隔符,默认为" "空格,如上图所见,我们将字段分隔符设置为\n换行符,所以第一行原本以空格为字段分隔的内容就分别输出到单独一行了。然后是$N其中N为相应的字段号,这也是awk的内建变量,它表示引用相应的字段,因为我们这里第一行只有三个字段,所以只引用到了$3。除此之外另一个这里没有出现的$0,它表示引用当前记录(当前行)的全部内容。

    • 将test的第二行的以点为分段的字段换成以空格为分隔

    $ awk -F'.' '{ > if(NR==2){ > print $1 "\t" $2 "\t" $3 > }}' test # 或者 $ awk ' > BEGIN{ > FS="." > OFS="\t" # 如果写为一行,两个动作语句之间应该以";"号分开 > }{ > if(NR==2){ > print $1, $2, $3 > }}' test

    说明:这里的-F参数,前面已经介绍过,它是用来预先指定待处理记录的字段分隔符。我们需要注意的是除了指定OFS我们还可以在print 语句中直接打印特殊符号如这里的\t,print打印的非变量内容都需要用""一对引号包围起来。上面另一个版本,展示了实现预先指定变量分隔符的另一种方式,即使用BEGIN,就这个表达式指示了,其后的动作将在所有动作之前执行,这里是FS赋值了新的"."点号代替默认的" "空格

    注意:首先说明一点,我们在学习和使用awk的时候应该尽可能将其作为一门程序语言来理解,这样将会使你学习起来更容易,所以初学阶段在练习awk时应该尽量按照我那样的方式分多行按照一般程序语言的换行和缩进来输入,而不是全部写到一行(当然这在你熟练了之后是没有任何问题的)。

     

    5.5 awk常用的内置变量

    变量名

    说明

    FILENAME

    当前输入文件名,若有多个文件,则只表示第一个。如果输入是来自标准输入,则为空字符串

    $0

    当前记录的内容

    $N

    N表示字段号,最大值为NF变量的值

    FS

    字段分隔符,由正则表达式表示,默认为" "空格

    RS

    输入记录分隔符,默认为"\n",即一行为一个记录

    NF

    当前记录字段数

    NR

    已经读入的记录数

    FNR

    当前输入文件的记录数,请注意它与NR的区别

    OFS

    输出字段分隔符,默认为" "空格

    ORS

    输出记录分隔符,默认为"\n"

    关于awk的内容本课程将只会包含这些内容,如果你想了解更多,请期待后续课程,或者参看一下链接内容:

     

     

    一、实验介绍

    1.1 实验内容

    介绍 Ubuntu 下软件安装的几种方式,及 apt,dpkg 工具的使用。

    1.2 实验知识点

    通常 Linux 上的软件安装主要有四种方式:

    • 在线安装
    • 从磁盘安装deb软件包
    • 从二进制软件包安装
    • 从源代码编译安装

    这几种安装方式各有优劣,而大多数软件包会采用多种方式发布软件,所以我们常常需要全部掌握这几种软件安装方式,以便适应各种环境。下面将介绍前三种安装方式,从源码编译安装你将在 Linux 程序设计中学习到。

     

     

     

    试想一下,平时我们在使用 Windows 的时候,想要安装一个软件,我们需要在网上去下载对应软件的安装包,接着安装的时候就是不断的去点击下一步,这些流程想必大家已经经历无数回了,但是在 Linux 下,一个命令加回车,等待一下,软件就安装好了,这就是方便的在线安装软件的方式。在学习这种安装方式之前有一点需要说明的是,在不同的linux发行版上面在线安装方式会有一些差异包括使用的命令及它们的包管理工具,因为我们的开发环境是基于ubuntu的,所以这里我们涉及的在线安装方式将只适用于ubuntu发行版,或其它基于ubuntu的发行版如国内的ubuntukylin(优麒麟),ubuntu又是基于debian的发行版,它使用的是debian的包管理工具dpkg,所以一些操作也适用与debian。而在一些采用其它包管理工具的发行版如redhat,centos,fedora等将不适用(redhat和centos使用rpm)。

     

     

    2.1 先体验一下

    比如我们想安装一个软件,名字叫做 w3m(w3m是一个命令行的简易网页浏览器),那么输入如下命令:

    $ sudo apt-get install w3m

    这样的操作你应该在前面的章节中看到过很多次了,它就表示将会安装一个软件包名为w3m的软件

    我们来看看命令执行后的效果:

    $ w3m www.shiyanlou.com/faq

    注意:如果你在安装一个软件之后,无法立即使用Tab键补全这个命令,你可以尝试先执行source ~/.zshrc,然后你就可以使用补全操作。

     

     

    2.2 apt 包管理工具介绍

    APT是Advance Packaging Tool(高级包装工具)的缩写,是Debian及其派生发行版的软件包管理器,APT可以自动下载,配置,安装二进制或者源代码格式的软件包,因此简化了Unix系统上管理软件的过程。APT最早被设计成dpkg的前端,用来处理deb格式的软件包。现在经过APT-RPM组织修改,APT已经可以安装在支持RPM的系统管理RPM包。这个包管理器包含以 apt- 开头的多个工具,如 apt-get apt-cacheapt-cdrom 等,在Debian系列的发行版中使用。

    当你在执行安装操作时,首先apt-get 工具会在本地的一个数据库中搜索关于 w3m 软件的相关信息,并根据这些信息在相关的服务器上下载软件安装,这里大家可能会一个疑问:既然是在线安装软件,为啥会在本地的数据库中搜索?要解释这个问题就得提到几个名词了:

    • 软件源镜像服务器
    • 软件源

    我们需要定期从服务器上下载一个软件包列表,使用 sudo apt-get update 命令来保持本地的软件包列表是最新的(有时你也需要手动执行这个操作,比如更换了软件源),而这个表里会有软件依赖信息的记录,对于软件依赖,我举个例子:我们安装 w3m 软件的时候,而这个软件需要 libgc1c2 这个软件包才能正常工作,这个时候 apt-get 在安装软件的时候会一并替我们安装了,以保证 w3m 能正常的工作。

     

     

    2.3 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给出的建议安装的软件包

     

     

     

    2.4 安装软件包

    关于安装,如前面演示的一样你只需要执行apt-get install <软件包名>即可,除了这一点,你还应该掌握的是如何重新安装软件包。 很多时候我们需要重新安装一个软件包,比如你的系统被破坏,或者一些错误的配置导致软件无法正常工作。

    你可以使用如下方式重新安装:

    $ sudo apt-get --reinstall install w3m

    另一个你需要掌握的是,如何在不知道软件包完整名的时候进行安装。通常我们是使用Tab键补全软件包名,后面会介绍更好的方法来搜索软件包。有时候你需要同时安装多个软件包,你还可以使用正则表达式匹配软件包名进行批量安装。

     

    2.5 软件升级

    # 更新软件源 $ sudo apt-get update # 升级没有依赖问题的软件包 $ sudo apt-get upgrade # 升级并解决依赖关系 $ sudo apt-get dist-upgrade

     

     

    2.6 卸载软件

    如果你现在觉得 w3m 这个软件不合自己的胃口,或者是找到了更好的,你需要卸载它,那么简单!同样是一个命令加回车 sudo apt-get remove w3m ,系统会有一个确认的操作,之后这个软件便“滚蛋了”。

    或者,你可以执行

    # 不保留配置文件的移除 $ sudo apt-get purge w3m # 或者 sudo apt-get --purge remove # 移除不再需要的被依赖的软件包 $ sudo apt-get autoremove

     

     

     

    当自己刚知道了一个软件,想下载使用,需要确认软件仓库里面有没有,就需要用到搜索功能了,命令如下:

    sudo apt-cache search softname1 softname2 softname3……

    apt-cache 命令则是针对本地数据进行相关操作的工具,search 顾名思义在本地的数据库中寻找有关 softname1 softname2 …… 相关软件的信息。现在我们试试搜索一下之前我们安装的软件 w3m ,如图:

    结果显示了4个 w3m 相关的软件,并且有相关软件的简介。

    关于在线安装的的内容我们就介绍这么多,想了解更多关于APT的内容,你可以参考:

     

     

    3.1 dpkg 介绍

    dpkg 是 Debian 软件包管理器的基础,它被伊恩·默多克创建于 1993 年。dpkg 与 RPM 十分相似,同样被用于安装、卸载和供给和 .deb 软件包相关的信息。

    dpkg 本身是一个底层的工具。上层的工具,像是 APT,被用于从远程获取软件包以及处理复杂的软件包关系。"dpkg"是"Debian Package"的简写。

    我们经常可以在网络上见到以deb形式打包的软件包,就需要使用dpkg命令来安装。

    dpkg常用参数介绍:

    参数

    说明

    -i

    安装指定deb包

    -R

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

    -r

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

    -I

    显示deb包文件的信息

    -s

    显示已安装软件的信息

    -S

    搜索已安装的软件包

    -L

    显示已安装软件包的目录信息

     

     

    3.2 使用dpkg安装deb软件包

    我们先使用apt-get加上-d参数只下载不安装,下载emacs编辑器的deb包,下载完成后,我们可以查看/var/cache/apt/archives/目录下的内容,如下图:

    然后我们将第一个deb拷贝到 /home/shiyanlou 目录下,并使用dpkg安装

    $ cp /var/cache/apt/archives/emacs24_24.5+1-6ubuntu1.1_amd64.deb ~ # 安装之前参看deb包的信息 $ sudo dpkg -I emacs24_24.5+1-6ubuntu1.1_amd64.deb

    如你所见,这个包还额外依赖了一些软件包,这意味着,如果主机目前没有这些被依赖的软件包,直接使用dpkg安装可能会存在一些问题,因为dpkg并不能为你解决依赖关系。

    # 使用dpkg安装 $ sudo dpkg -i emacs24_24.5+1-6ubuntu1.1_amd64.deb

    跟前面预料的一样,这里你可能出现了一些错误:

    我们将如何解决这个错误呢?这就要用到apt-get了,使用它的-f参数了,修复依赖关系的安装

    $ sudo apt-get update $ sudo apt-get -f install

    没有任何错误,这样我们就安装成功了,然后你可以运行emacs程序

     

     

    3.3 查看已安装软件包的安装目录

    如果你依然在纠结到底linux将软件安装到了什么地方,那么很幸运你将可以通过dpkg找到答案

    使用dpkg -L查看deb包目录信息

    $ sudo dpkg -L emacs24

    dpkg还有一些其他的参数,这里将作为练习题由你自己来学习

     

     

    四、从二进制包安装

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

     

     

    一、实验介绍

    1.1 实验内容

    Linux 中也难免遇到某个程序无响应的情况,可以通过一些命令来帮助我们让系统能够更流畅的运行。 而在此之前,我们需要对进程的基础知识有一定的了解,才能更好、更有效率的使用Linux 提供的工具。

    1.2实验知识点

    • 进程与程序
    • 进程的衍生
    • 工作管理

     

     

    二、概念的理解

    首先程序与进程是什么?程序与进程又有什么区别?

    程序(procedure):不太精确地说,程序就是执行一系列有逻辑、有顺序结构的指令,帮我们达成某个结果。就如我们去餐馆,给服务员说我要牛肉盖浇饭,她执行了做牛肉盖浇饭这么一个程序,最后我们得到了这么一盘牛肉盖浇饭。它需要去执行,不然它就像一本武功秘籍,放在那里等人翻看。

    进程(process):进程是程序在一个数据集合上的一次执行过程,在早期的UNIX、Linux 2.4及更早的版本中,它是系统进行资源分配和调度的独立基本单位。同上一个例子,就如我们去了餐馆,给服务员说我要牛肉盖浇饭,她执行了做牛肉盖浇饭这么一个程序,而里面做饭的是一个进程,做牛肉汤汁的是一个进程,把牛肉汤汁与饭混合在一起的是一个进程,把饭端上桌的是一个进程。它就像是我们在看武功秘籍这么一个过程,然后一个篇章一个篇章地去练。

    简单来说,程序是为了完成某种任务而设计的软件,比如 vim 是程序。什么是进程呢?进程就是运行中的程序。

    程序只是一些列指令的集合,是一个静止的实体,而进程不同,进程有以下的特性:

    • 动态性:进程的实质是一次程序执行的过程,有创建、撤销等状态的变化。而程序是一个静态的实体。
    • 并发性:进程可以做到在一个时间段内,有多个程序在运行中。程序只是静态的实体,所以不存在并发性。
    • 独立性:进程可以独立分配资源,独立接受调度,独立地运行。
    • 异步性:进程以不可预知的速度向前推进。
    • 结构性:进程拥有代码段、数据段、PCB(进程控制块,进程存在的唯一标志)。也正是因为有结构性,进程才可以做到独立地运行。

    并发:在一个时间段内,宏观来看有多个程序都在活动,有条不紊的执行(每一瞬间只有一个在执行,只是在一段时间有多个程序都执行过)

    并行:在每一个瞬间,都有多个程序都在同时执行,这个必须有多个 CPU 才行

    引入进程是因为传统意义上的程序已经不足以描述 OS 中各种活动之间的动态性、并发性、独立性还有相互制约性。程序就像一个公司,只是一些证书,文件的堆积(静态实体)。而当公司运作起来就有各个部门的区分,财务部,技术部,销售部等等,就像各个进程,各个部门之间可以独立运做,也可以有交互(独立性、并发性)。

    而随着程序的发展越做越大,又会继续细分,从而引入了线程的概念,当代多数操作系统、Linux 2.6及更新的版本中,进程本身不是基本运行单位,而是线程的容器。就像上述所说的,每个部门又会细分为各个工作小组(线程),而工作小组需要的资源需要向上级(进程)申请。

    线程(thread)是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。因为线程中几乎不包含系统资源,所以执行更快、更有效率。

    简而言之,一个程序至少有一个进程,一个进程至少有一个线程。线程的划分尺度小于进程,使得多线程程序的并发性高。另外,进程在执行过程中拥有独立的内存单元,而多个线程共享内存,从而极大地提高了程序的运行效率。就如下图所示:

     

     

     

    3.1 进程的分类

    大概明白进程是个什么样的存在后,我们需要进一步了解的就是进程分类。可以从两个角度来分:

    • 以进程的功能与服务的对象来分;
    • 以应用程序的服务类型来分;

    第一个角度来看,我们可以分为用户进程与系统进程:

    • 用户进程:通过执行用户程序、应用程序或称之为内核之外的系统程序而产生的进程,此类进程可以在用户的控制下运行或关闭。
    • 系统进程:通过执行系统内核程序而产生的进程,比如可以执行内存资源分配和进程切换等相对底层的工作;而且该进程的运行不受用户的干预,即使是 root 用户也不能干预系统进程的运行。

    第二角度来看,我们可以将进程分为交互进程、批处理进程、守护进程

    • 交互进程:由一个 shell 终端启动的进程,在执行过程中,需要与用户进行交互操作,可以运行于前台,也可以运行在后台。
    • 批处理进程:该进程是一个进程集合,负责按顺序启动其他的进程。
    • 守护进程:守护进程是一直运行的一种进程,在 Linux 系统启动时启动,在系统关闭时终止。它们独立于控制终端并且周期性的执行某种任务或等待处理某些发生的事件。例如 httpd 进程,一直处于运行状态,等待用户的访问。还有经常用的 cron(在 centOS 系列为 crond)进程,这个进程为 crontab 的守护进程,可以周期性的执行用户设定的某些任务。

     

     

    3.2 进程的衍生

    进程有这么多的种类,那么进程之间定是有相关性的,而这些有关联性的进程又是如何产生的,如何衍生的?

    就比如我们启动了终端,就是启动了一个 bash 进程,我们可以在 bash 中再输入 bash 则会再启动一个 bash 的进程,此时第二个 bash 进程就是由第一个 bash 进程创建出来的,他们之间又是个什么关系?

    我们一般称呼第一个 bash 进程是第二 bash 进程的父进程,第二 bash 进程是第一个 bash 进程的子进程,这层关系是如何得来的呢?

    关于父进程与子进程便会提及这两个系统调用 fork() 与 exec()

    fork-exec是由 Dennis M. Ritchie 创造的

    fork() 是一个系统调用(system call),它的主要作用就是为当前的进程创建一个新的进程,这个新的进程就是它的子进程,这个子进程除了父进程的返回值和 PID 以外其他的都一模一样,如进程的执行代码段,内存信息,文件描述,寄存器状态等等

    exec() 也是系统调用,作用是切换子进程中的执行程序也就是替换其从父进程复制过来的代码段与数据段

    子进程就是父进程通过系统调用 fork() 而产生的复制品,fork() 就是把父进程的 PCB 等进程的数据结构信息直接复制过来,只是修改了 PID,所以一模一样,只有在执行 exec() 之后才会不同,而早先的 fork() 比较消耗资源后来进化成 vfork(),效率高了不少,感兴趣的同学可以查查为什么。

    这就是子进程产生的由来。简单的实现逻辑就如下方所示【注释1】

    pid_t p; p = fork(); if (p == (pid_t) -1) /* ERROR */ else if (p == 0) /* CHILD */ else /* PARENT */

    既然子进程是通过父进程而衍生出来的,那么子进程的退出与资源的回收定然与父进程有很大的相关性。当一个子进程要正常的终止运行时,或者该进程结束时它的主函数 main() 会执行 exit(n); 或者 return n,这里的返回值 n 是一个信号,系统会把这个 SIGCHLD 信号传给其父进程,当然若是异常终止也往往是因为这个信号。

    在将要结束时的子进程代码执行部分已经结束执行了,系统的资源也基本归还给系统了,但若是其进程的进程控制块(PCB)仍驻留在内存中,而它的 PCB 还在,代表这个进程还存在(因为 PCB 就是进程存在的唯一标志,里面有 PID 等消息),并没有消亡,这样的进程称之为僵尸进程(Zombie)。

    如图中第四列标题是 S,S 表示的是进程的状态,而在下属的第三行的 Z 表示的是 Zombie 的意思。( ps 命令将在后续详解)

    正常情况下,父进程会收到两个返回值:exit code(SIGCHLD 信号)与 reason for termination 。之后,父进程会使用 wait(&status) 系统调用以获取子进程的退出状态,然后内核就可以从内存中释放已结束的子进程的 PCB;而如若父进程没有这么做的话,子进程的 PCB 就会一直驻留在内存中,一直留在系统中成为僵尸进程(Zombie)。

    虽然僵尸进程是已经放弃了几乎所有内存空间,没有任何可执行代码,也不能被调度,在进程列表中保留一个位置,记载该进程的退出状态等信息供其父进程收集,从而释放它。但是 Linux 系统中能使用的 PID 是有限的,如果系统中存在有大量的僵尸进程,系统将会因为没有可用的 PID 从而导致不能产生新的进程。

    另外如果父进程结束(非正常的结束),未能及时收回子进程,子进程仍在运行,这样的子进程称之为孤儿进程。在 Linux 系统中,孤儿进程一般会被 init 进程所“收养”,成为 init 的子进程。由 init 来做善后处理,所以它并不至于像僵尸进程那样无人问津,不管不顾,大量存在会有危害。

    进程 0 是系统引导时创建的一个特殊进程,也称之为内核初始化,其最后一个动作就是调用 fork() 创建出一个子进程运行 /sbin/init 可执行文件,而该进程就是 PID=1 的进程 1,而进程 0 就转为交换进程(也被称为空闲进程),进程 1 (init 进程)是第一个用户态的进程,再由它不断调用 fork() 来创建系统里其他的进程,所以它是所有进程的父进程或者祖先进程。同时它是一个守护程序,直到计算机关机才会停止。

    通过以下的命令我们可以很明显的看到这样的结构

    pstree

    或者从此图我们可以更加形象的看清子父进程的关系

    通过以上的显示结果我们可以看的很清楚,init 为所有进程的父进程或者说是祖先进程

    我们还可以使用这样一个命令来看,其中 pid 就是该进程的一个唯一编号,ppid 就是该进程的父进程的 pid,command 表示的是该进程通过执行什么样的命令或者脚本而产生的

    ps -fxo user,ppid,pid,pgid,command

    可以在图中看见我们执行的 ps 就是由 zsh 通过 fork-exec 创建的子进程而执行的

    使用这样的一个命令我们也能清楚的看见 init 如上文所说是由进程 0 这个初始化进程来创建出来的子进程,而其他的进程基本是由 init 创建的子进程,或者是由它的子进程创建出来的子进程。所以 init 是用户进程的第一个进程也是所有用户进程的父进程或者祖先进程。(ps 命令将在后续课程详解)

    就像一个树状图,而 init 进程就是这棵树的根,其他进程由根不断的发散,开枝散叶

     

     

    3.3 进程组与 Sessions

    每一个进程都会是一个进程组的成员,而且这个进程组是唯一存在的,他们是依靠 PGID(process group ID)来区别的,而每当一个进程被创建的时候,它便会成为其父进程所在组中的一员。

    一般情况,进程组的 PGID 等同于进程组的第一个成员的 PID,并且这样的进程称为该进程组的领导者,也就是领导进程,进程一般通过使用 getpgrp() 系统调用来寻找其所在组的 PGID,领导进程可以先终结,此时进程组依然存在,并持有相同的PGID,直到进程组中最后一个进程终结。

    与进程组类似,每当一个进程被创建的时候,它便会成为其父进程所在 Session 中的一员,每一个进程组都会在一个 Session 中,并且这个 Session 是唯一存在的,

    Session 主要是针对一个 tty 建立,Session 中的每个进程都称为一个工作(job)。每个会话可以连接一个终端(control terminal)。当控制终端有输入输出时,都传递给该会话的前台进程组。Session 意义在于将多个 jobs 囊括在一个终端,并取其中的一个 job 作为前台,来直接接收该终端的输入输出以及终端信号。 其他 jobs 在后台运行。

    前台(foreground)就是在终端中运行,能与你有交互的

    后台(background)就是在终端中运行,但是你并不能与其任何的交互,也不会显示其执行的过程

     

     

     

    3.4 工作管理

    bash(Bourne-Again shell)支持工作控制(job control),而 sh(Bourne shell)并不支持。

    并且每个终端或者说 bash 只能管理当前终端中的 job,不能管理其他终端中的 job。比如我当前存在两个 bash 分别为 bash1、bash2,bash1 只能管理其自己里面的 job 并不能管理 bash2 里面的 job

    我们都知道当一个进程在前台运作时我们可以用 ctrl + c 来终止它,但是若是在后台的话就不行了。

    我们可以通过 & 这个符号,让我们的命令在后台中运行

    ls &

    图中所显示的 [1] 236分别是该 job 的 job number 与该进程的 PID,而最后一行的 Done 表示该命令已经在后台执行完毕。

    我们还可以通过 ctrl + z 使我们的当前工作停止并丢到后台中去

    被停止并放置在后台的工作我们可以使用这个命令来查看

    jobs

    其中第一列显示的为被放置后台 job 的编号,而第二列的 + 表示最近(刚刚、最后)被放置后台的 job,同时也表示预设的工作,也就是若是有什么针对后台 job 的操作,首先对预设的 job,- 表示倒数第二(也就是在预设之前的一个)被放置后台的工作,倒数第三个(再之前的)以后都不会有这样的符号修饰,第三列表示它们的状态,而最后一列表示该进程执行的命令

    我们可以通过这样的一个命令将后台的工作拿到前台来

    #后面不加参数提取预设工作,加参数提取指定工作的编号 #ubuntu 在 zsh 中需要 %,在 bash 中不需要 % fg [%jobnumber]

    之前我们通过 ctrl + z 使得工作停止放置在后台,若是我们想让其在后台运作我们就使用这样一个命令

    #与fg类似,加参则指定,不加参则取预设 bg [%jobnumber]

    既然有方法将被放置在后台的工作提至前台或者让它从停止变成继续运行在后台,当然也有方法删除一个工作,或者重启等等

    #kill的使用格式如下 kill -signal %jobnumber #signal从1-64个信号值可以选择,可以这样查看 kill -l

    其中常用的有这些信号值

    信号值

    作用

    -1

    重新读取参数运行,类似与restart

    -2

    如同 ctrl+c 的操作退出

    -9

    强制终止该任务

    -15

    正常的方式终止该任务

    注意

    若是在使用kill+信号值然后直接加 pid,你将会对 pid 对应的进程进行操作

    若是在使用kill+信号值然后 %jobnumber,这时所操作的对象是 job,这个数字就是就当前 bash 中后台的运行的 job 的 ID

     

     

    一、实验介绍

    1.1 实验内容

    通过本实验我们将掌握一些 Linux 所提供的工具来进行进程的查看与控制,掌握这些工具让我们能在某些进程出现异常的时候及时查看相关的指标,从而解决问题。

    1.2 实验知识点

    • 查看进程的运行状态
    • 进程的结束控制
    • 进程的执行顺序

     

     

    不管在测试的时候、在实际的生产环境中,还是自己的使用过程中,难免会遇到一些进程异常的情况,所以 Linux 为我们提供了一些工具来查看进程的状态信息。我们可以通过 top 实时的查看进程的状态,以及系统的一些信息(如 CPU、内存信息等),我们还可以通过 ps 来静态查看当前的进程信息,同时我们还可以使用 pstree 来查看当前活跃进程的树形结构。

     

     

    2.1 top 工具的使用

    top 工具是我们常用的一个查看工具,能实时的查看我们系统的一些关键信息的变化:

    top

    top 是一个在前台执行的程序,所以执行后便进入到这样的一个交互界面,正是因为交互界面我们才可以实时的获取到系统与进程的信息。在交互界面中我们可以通过一些指令来操作和筛选。在此之前我们先来了解显示了哪些信息。

    我们看到 top 显示的第一排,

    内容

    解释

    top

    表示当前程序的名称

    11:05:18

    表示当前的系统的时间

    up 8 days,17:12

    表示该机器已经启动了多长时间

    1 user

    表示当前系统中只有一个用户

    load average: 0.29,0.20,0.25

    分别对应1、5、15分钟内cpu的平均负载

    load average 在 wikipedia 中的解释是 the system load is a measure of the amount of work that a computer system is doing 也就是对当前 CPU 工作量的度量,具体来说也就是指运行队列的平均长度,也就是等待 CPU 的平均进程数相关的一个计算值。

    我们该如何看待这个load average 数据呢?

    假设我们的系统是单 CPU、单内核的,把它比喻成是一条单向的桥,把CPU任务比作汽车。

    • load = 0 的时候意味着这个桥上并没有车,cpu 没有任何任务;
    • load < 1 的时候意味着桥上的车并不多,一切都还是很流畅的,cpu 的任务并不多,资源还很充足;
    • load = 1 的时候就意味着桥已经被车给占满了,没有一点空隙,cpu 的已经在全力工作了,所有的资源都被用完了,当然还好,这还在能力范围之内,只是有点慢而已;
    • load > 1 的时候就意味着不仅仅是桥上已经被车占满了,就连桥外都被占满了,cpu 已经在全力工作,系统资源的用完了,但是还是有大量的进程在请求,在等待。若是这个值大于2、大于3,表示进程请求超过 CPU 工作能力的 2 到 3 倍。而若是这个值 > 5 说明系统已经在超负荷运作了。

    这是单个 CPU 单核的情况,而实际生活中我们需要将得到的这个值除以我们的核数来看。我们可以通过以下的命令来查看 CPU 的个数与核心数

    #查看物理CPU的个数 #cat /proc/cpuinfo |grep "physical id"|sort |uniq|wc -l #每个cpu的核心数 cat /proc/cpuinfo |grep "physical id"|grep "0"|wc -l

    通过上面的指数我们可以得知 load 的临界值为 1 ,但是在实际生活中,比较有经验的运维或者系统管理员会将临界值定为0.7。这里的指数都是除以核心数以后的值,不要混淆了

    • 若是 load < 0.7 并不会去关注他;
    • 若是 0.7< load < 1 的时候我们就需要稍微关注一下了,虽然还可以应付但是这个值已经离临界不远了;
    • 若是 load = 1 的时候我们就需要警惕了,因为这个时候已经没有更多的资源的了,已经在全力以赴了;
    • 若是 load > 5 的时候系统已经快不行了,这个时候你需要加班解决问题了

    通常我们都会先看 15 分钟的值来看这个大体的趋势,然后再看 5 分钟的值对比来看是否有下降的趋势。

    查看 busybox 的代码可以知道,数据是每 5 秒钟就检查一次活跃的进程数,然后计算出该值,然后 load 从 /proc/loadavg 中读取的。而这个 load 的值是如何计算的呢,这是 load 的计算的源码

    #define FSHIFT 11 /* nr of bits of precision */ #define FIXED_1 (1<<FSHIFT) /* 1.0 as fixed-point(定点) */ #define LOAD_FREQ (5*HZ) /* 5 sec intervals,每隔5秒计算一次平均负载值 */ #define CALC_LOAD(load, exp, n) \ load *= exp; \ load += n*(FIXED_1 - exp); \ load >>= FSHIFT; unsigned long avenrun[3]; EXPORT_SYMBOL(avenrun); /* * calc_load - given tick count, update the avenrun load estimates. * This is called while holding a write_lock on xtime_lock. */ static inline void calc_load(unsigned long ticks) { unsigned long active_tasks; /* fixed-point */ static int count = LOAD_FREQ; count -= ticks; if (count < 0) { count += LOAD_FREQ; active_tasks = count_active_tasks(); CALC_LOAD(avenrun[0], EXP_1, active_tasks); CALC_LOAD(avenrun[1], EXP_5, active_tasks); CALC_LOAD(avenrun[2], EXP_15, active_tasks); } }

    有兴趣的朋友可以研究一下,是如何计算的。代码中的后面这部分相当于它的计算公式

    我们回归正题,来看 top 的第二行数据,基本上第二行是进程的一个情况统计

    内容

    解释

    Tasks: 26 total

    进程总数

    1 running

    1个正在运行的进程数

    25 sleeping

    25个睡眠的进程数

    0 stopped

    没有停止的进程数

    0 zombie

    没有僵尸进程数

    来看 top 的第三行数据,这一行基本上是 CPU 的一个使用情况的统计了

    内容

    解释

    Cpu(s): 1.0%us

    用户空间进程占用CPU百分比

    1.0% sy

    内核空间运行占用CPU百分比

    0.0%ni

    用户进程空间内改变过优先级的进程占用CPU百分比

    97.9%id

    空闲CPU百分比

    0.0%wa

    等待输入输出的CPU时间百分比

    0.1%hi

    硬中断(Hardware IRQ)占用CPU的百分比

    0.0%si

    软中断(Software IRQ)占用CPU的百分比

    0.0%st

    (Steal time) 是 hypervisor 等虚拟服务中,虚拟 CPU 等待实际 CPU 的时间的百分比

    CPU 利用率是对一个时间段内 CPU 使用状况的统计,通过这个指标可以看出在某一个时间段内 CPU 被占用的情况,而 Load Average 是 CPU 的 Load,它所包含的信息不是 CPU 的使用率状况,而是在一段时间内 CPU 正在处理以及等待 CPU 处理的进程数情况统计信息,这两个指标并不一样。

    来看 top 的第四行数据,这一行基本上是内存的一个使用情况的统计了:

    内容

    解释

    8176740 total

    物理内存总量

    8032104 used

    使用的物理内存总量

    144636 free

    空闲内存总量

    313088 buffers

    用作内核缓存的内存量

    注意

    系统中可用的物理内存最大值并不是 free 这个单一的值,而是 free + buffers + swap 中的 cached 的和

    来看 top 的第五行数据,这一行基本上是交换区的一个使用情况的统计了

    内容

    解释

    total

    交换区总量

    used

    使用的交换区总量

    free

    空闲交换区总量

    cached

    缓冲的交换区总量,内存中的内容被换出到交换区,而后又被换入到内存,但使用过的交换区尚未被覆盖

    再下面就是进程的一个情况了

    列名

    解释

    PID

    进程id

    USER

    该进程的所属用户

    PR

    该进程执行的优先级 priority 值

    NI

    该进程的 nice 值

    VIRT

    该进程任务所使用的虚拟内存的总数

    RES

    该进程所使用的物理内存数,也称之为驻留内存数

    SHR

    该进程共享内存的大小

    S

    该进程进程的状态: S=sleep R=running Z=zombie

    %CPU

    该进程CPU的利用率

    %MEM

    该进程内存的利用率

    TIME+

    该进程活跃的总时间

    COMMAND

    该进程运行的名字

    注意

    NICE 值叫做静态优先级,是用户空间的一个优先级值,其取值范围是-20至19。这个值越小,表示进程”优先级”越高,而值越大“优先级”越低。nice值中的 -20 到 19,中 -20 优先级最高, 0 是默认的值,而 19 优先级最低

    PR 值表示 Priority 值叫动态优先级,是进程在内核中实际的优先级值,进程优先级的取值范围是通过一个宏定义的,这个宏的名称是 MAX_PRIO,它的值为 140。Linux 实际上实现了 140 个优先级范围,取值范围是从 0-139,这个值越小,优先级越高。而这其中的 0 - 99 是实时进程的值,而 100 - 139 是给用户的。

    其中 PR 中的 100 to 139 值部分有这么一个对应 PR = 20 + (-20 to +19),这里的 -20 to +19 便是nice值,所以说两个虽然都是优先级,而且有千丝万缕的关系,但是他们的值,他们的作用范围并不相同

    ** VIRT **任务所使用的虚拟内存的总数,其中包含所有的代码,数据,共享库和被换出 swap空间的页面等所占据空间的总数

    在上文我们曾经说过 top 是一个前台程序,所以是一个可以交互的

    常用交互命令

    解释

    q

    退出程序

    I

    切换显示平均负载和启动时间的信息

    P

    根据CPU使用百分比大小进行排序

    M

    根据驻留内存大小进行排序

    i

    忽略闲置和僵死的进程,这是一个开关式命令

    k

    终止一个进程,系统提示输入 PID 及发送的信号值。一般终止进程用 15 信号,不能正常结束则使用 9 信号。安全模式下该命令被屏蔽。

    好好的利用 top 能够很有效的帮助我们观察到系统的瓶颈所在,或者是系统的问题所在。

     

     

     

     

    ps 也是我们最常用的查看进程的工具之一,我们通过这样的一个命令来了解一下,他能给我带来哪些信息

    ps aux

    ps axjf

    我们来总体了解下会出现哪些信息给我们,这些信息又代表着什么(更多的 keywords 大家可以通过 man ps 了解)

    内容

    解释

    F

    进程的标志(process flags),当 flags 值为 1 则表示此子程序只是 fork 但没有执行 exec,为 4 表示此程序使用超级管理员 root 权限

    USER

    进程的拥有用户

    PID

    进程的 ID

    PPID

    其父进程的 PID

    SID

    session 的 ID

    TPGID

    前台进程组的 ID

    %CPU

    进程占用的 CPU 百分比

    %MEM

    占用内存的百分比

    NI

    进程的 NICE 值

    VSZ

    进程使用虚拟内存大小

    RSS

    驻留内存中页的大小

    TTY

    终端 ID

    S or STAT

    进程状态

    WCHAN

    正在等待的进程资源

    START

    启动进程的时间

    TIME

    进程消耗CPU的时间

    COMMAND

    命令的名称和参数

    TPGID栏写着-1的都是没有控制终端的进程,也就是守护进程

    STAT表示进程的状态,而进程的状态有很多,如下表所示

    状态

    解释

    R

    Running.运行中

    S

    Interruptible Sleep.等待调用

    D

    Uninterruptible Sleep.不可中断睡眠

    T

    Stoped.暂停或者跟踪状态

    X

    Dead.即将被撤销

    Z

    Zombie.僵尸进程

    W

    Paging.内存交换

    N

    优先级低的进程

    <

    优先级高的进程

    s

    进程的领导者

    L

    锁定状态

    l

    多线程状态

    +

    前台进程

    其中的 D 是不能被中断睡眠的状态,处在这种状态的进程不接受外来的任何 signal,所以无法使用 kill 命令杀掉处于D状态的进程,无论是 kill,kill -9 还是 kill -15,一般处于这种状态可能是进程 I/O 的时候出问题了。

    ps 工具有许多的参数,下面给大家解释部分常用的参数

    使用 -l 参数可以显示自己这次登陆的 bash 相关的进程信息罗列出来

    ps -l

    相对来说我们更加常用下面这个命令,他将会罗列出所有的进程信息

    ps aux

    若是查找其中的某个进程的话,我们还可以配合着 grep 和正则表达式一起使用

    ps aux | grep zsh

    此外我们还可以查看时,将连同部分的进程呈树状显示出来

    ps axjf

    当然如果你觉得使用这样的此时没有把你想要的信息放在一起,我们也可以是用这样的命令,来自定义我们所需要的参数显示

    ps -afxo user,ppid,pid,pgid,command

    这是一个简单而又实用的工具,想要更灵活的使用,想要知道更多的参数我们可以使用 man 来获取更多相关的信息

     

     

    2.3 pstree 工具的使用

    通过 pstree 可以很直接的看到相同的进程数量,最主要的还是我们可以看到所有进程之间的相关性。

    pstree

    pstree -up #参数选择: #-A :各程序树之间以 ASCII 字元來連接; #-p :同时列出每个 process 的 PID; #-u :同时列出每个 process 的所屬账户名称。

     

     

     

    3.1 kill 命令的掌握

    上个实验中我们讲诉了进程之间是如何衍生,之间又有什么相关性,我们来回顾一下,当一个进程结束的时候或者要异常结束的时候,会向其父进程返回一个或者接收一个 SIGHUP 信号而做出的结束进程或者其他的操作,这个 SIGHUP 信号不仅可以由系统发送,我们可以使用 kill 来发送这个信号来操作进程的结束或者重启等等。

    上节课程我们使用 kill 命令来管理我们的一些 job,这节课我们将尝试用 kill 来操作下一些不属于 job 范畴的进程,直接对 pid 下手

    #首先我们使用图形界面打开了 gedit、gvim,用 ps 可以查看到 ps aux #使用9这个信号强制结束 gedit 进程 kill -9 1608 #我们再查找这个进程的时候就找不到了 ps aux | grep gedit

     

     

     

    3.2 进程的执行顺序

    我们在使用 ps 命令的时候可以看到大部分的进程都是处于休眠的状态,如果这些进程都被唤醒,那么该谁最先享受 CPU 的服务,后面的进程又该是一个什么样的顺序呢?进程调度的队列又该如何去排列呢?

    当然就是靠该进程的优先级值来判定进程调度的优先级,而优先级的值就是上文所提到的 PR 与 nice 来控制与体现了

    而 nice 的值我们是可以通过 nice 命令来修改的,而需要注意的是 nice 值可以调整的范围是 -20 ~ 19,其中 root 有着至高无上的权力,既可以调整自己的进程也可以调整其他用户的程序,并且是所有的值都可以用,而普通用户只可以调制属于自己的进程,并且其使用的范围只能是 0 ~ 19,因为系统为了避免一般用户抢占系统资源而设置的一个限制

    #这个实验在环境中无法做,因为权限不够,可以自己在本地尝试 #打开一个程序放在后台,或者用图形界面打开 nice -n -5 vim & #用 ps 查看其优先级 ps -afxo user,ppid,pid,stat,pri,ni,time,command | grep vim

    我们还可以用 renice 来修改已经存在的进程的优先级,同样因为权限的原因在实验环境中无法尝试

    renice -5 pid

     

     

    一、实验介绍

    1.1 实验内容

    日志数据可以是有价值的信息宝库,也可以是毫无价值的数据泥潭。它可以记录下系统产生的所有行为,并按照某种规范表达出来。我们可以使用日志系统所记录的信息为系统进行排错,优化系统的性能,或者根据这些信息调整系统的行为。收集你想要的数据,分析出有价值的信息,可以提高系统、产品的安全性,还可以帮助开发完善代码,优化产品。日志会成为在事故发生后查明“发生了什么”的一个很好的“取证”信息来源。日志可以为审计进行审计跟踪。

    1.2 实验知识点

    • 常见的日志
    • 配置的日志
    • 轮替的日志

    二、常见的日志

    日志是一个系统管理员,一个运维人员,甚至是开发人员不可或缺的东西,系统用久了偶尔也会出现一些错误,我们需要日志来给系统排错,在一些网络应用服务不能正常工作的时候,我们需要用日志来做问题定位,日志还是过往时间的记录本,我们可以通过它知道我们是否被不明用户登录过等等。

    在 Linux 中大部分的发行版都内置使用 syslog 系统日志,那么通过前期的课程我们了解到常见的日志一般存放在 /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

    系统信息记录

    而在本实验环境中没有 apport.log 是因为 apport 这个应用程序需要读取一些内核的信息来收集判断其他应用程序的信息,从而记录应用程序的崩溃信息。而在本实验环境中我们没有这个权限,所以将 apport 从内置应用值剔除,自然而然就没有它的日志信息了。

    只闻其名,不见其人,我们并不能明白这些日志记录的内容。首先我们来看 alternatives.log 中的信息,在本实验环境中没有任何日志输出是因为刚刚启动的系统中并没有任何的更新迭代。我可以看看从其他地方截取过来的内容

    update-alternatives 2016-07-02 13:36:16: run with --install /usr/bin/x-www-browser x-www-browser /usr/bin/google-chrome-stable 200 update-alternatives 2016-07-02 13:36:16: run with --install /usr/bin/gnome-www-browser gnome-www-browser /usr/bin/google-chrome-stable 200 update-alternatives 2016-07-02 13:36:16: run with --install /usr/bin/google-chrome google-chrome /usr/bin/google-chrome-stable 200

    我们可以从中得到的信息有程序作用,日期,命令,成功与否的返回码

    我们用这样的命令来看看 auth.log 中的信息

    less auth.log

    我们可以从中得到的信息有日期与 ip 地址的来源以及的用户与工具

    在 apt 文件夹中的日志信息,其中有两个日志文件 history.log 与 term.log,两个日志文件的区别在于 history.log 主要记录了进行了哪个操作,相关的依赖有哪些,而 term.log 则是较为具体的一些操作,主要就是下载包,打开包,安装包等等的细节操作。

    我们通过这样的例子就可以很明显的看出区别,在本实验环境中因为是刚启动的环境,所以两个日志中的信息都是空的

    less /var/log/apt/history.log less /var/log/apt/term.log

    然后我们来安装 git 这个程序,因为本实验环境中本有预装 git 所以这里真正执行的操作是一个更新的操作,但这并不影响

    sudo apt-get install git

    成功的执行之后我们再来查看两个日志的内容变化

    其他的日志格式也都类似于之前我们所查看的日志,主要便是时间,操作。而这其中有两个比较特殊的日志,其查看的方式比较与众不同,因为这两个日志并不是 ASCII 文件而是被编码成了二进制文件,所以我们并不能直接使用 less、cat、more 这样的工具来查看,这两个日志文件是 wtmp,lastlog

    我们查看的方法是使用 last 与 lastlog 工具来提取其中的信息

    关于这两个工具的更深入使用我们可以使用前面的学习过的 man 来查看

     

    三、配置的日志

    这些日志是如何产生的?通过上面的例子我们可以看出大部分的日志信息似乎格式都很类似,并且都出现在这个文件夹中。

    这样的实现可以通过两种方式:

    • 一种是由软件开发商自己来自定义日志格式然后指定输出日志位置;
    • 一种方式就是 Linux 提供的日志服务程序,而我们这里系统日志是通过 syslog 来实现,提供日志管理服务。

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

    rsyslog的全称是 rocket-fast system for log,它提供了高性能,高安全功能和模块化设计。rsyslog 能够接受各种各样的来源,将其输入,输出的结果到不同的目的地。rsyslog 可以提供超过每秒一百万条消息给目标文件。

    这样能实时收集日志信息的程序是有其守护进程的,如 rsyslog 的守护进程便是 rsyslogd

    因为一些原因本实验环境中默认并没有打开这个服务,我们可以手动开启这项服务,然后来查看

    sudo apt-get update sudo apt-get install -y rsyslog sudo service rsyslog start ps aux | grep syslog

    既然它是一个服务,那么它便是可以配置,为我们提供一些我们自定义的服务

    首先我们来看 rsyslog 的配置文件是什么样子的,而 rsyslog 的配置文件有两个,

    • 一个是 /etc/rsyslog.conf
    • 一个是 /etc/rsyslog.d/50-default.conf。

    第一个主要是配置的环境,也就是 rsyslog 加载什么模块,文件的所属者等;而第二个主要是配置的 Filter Conditions

    vim /etc/rsyslog.conf vim /etc/rsyslog.d/50-default.conf

    也不知道他在写什么,我们还是来看看 rsyslog 的结构框架,数据流的走向吧。

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

    上文提到过 rsyslog 号称可以提供超过每秒一百万条消息给目标文件,怎么只是这样简单的结构。我们可以通过下图来做更深入的了解

    (图片来源于http://www.rsyslog.com/doc/queues_analogy.html

    Rsyslog 架构如图中所示,从图中我们可以很清楚的看见,rsyslog 还有一个核心的功能模块便是 Queue,也正是因为它才能做到如此高的并发。

    第一个模块便是 Input,该模块的主要功能就是从各种各样的来源收集 messages,通过这些接口实现:

    接口名

    作用

    im3195

    RFC3195 Input Module

    imfile

    Text File Input Module

    imgssapi

    GSSAPI Syslog Input Module

    imjournal

    Systemd Journal Input Module

    imklog

    Kernel Log Input Module

    imkmsg

    /dev/kmsg Log Input Module

    impstats

    Generate Periodic Statistics of Internal Counters

    imptcp

    Plain TCP Syslog

    imrelp

    RELP Input Module

    imsolaris

    Solaris Input Module

    imtcp

    TCP Syslog Input Module

    imudp

    UDP Syslog Input Module

    imuxsock

    Unix Socket Input

    而 Output 中也有许多可用的接口,可以通过 man 或者官方的文档查看

    而这些模块接口的使用需要通过 $ModLoad 指令来加载,那么返回上文的图中,配置生效的头两行可以看懂了,默认加载了 imklog、imuxsock 这两个模块

    在配置中 rsyslog 支持三种配置语法格式:

    • sysklogd
    • legacy rsyslog
    • RainerScript

    sysklogd 是老的简单格式,一些新的语法特性不支持。而 legacy rsyslog 是以 dollar 符($)开头的语法,在 v6 及以上的版本还在支持,就如上文所说的 $ModLoad 还有一些插件和特性只在此语法下支持。而以 $ 开头的指令是全局指令,全局指令是 rsyslogd 守护进程的配置指令,每行只能有一个指令。 RainnerScript 是最新的语法。在官网上 rsyslog 大多推荐这个语法格式来配置

    老的语法格式(sysklogd & legacy rsyslog)是以行为单位。新的语法格式(RainnerScript)可以分割多行。

    注释有两种语法:

    • 井号 #
    • C-style /* .. */

    执行顺序: 指令在 rsyslog.conf 文件中是从上到下的顺序执行的。

    模板是 rsyslog 一个重要的属性,它可以控制日志的格式,支持类似 template() 语句的基于 string 或 plugin 的模板,通过它我们可以自定义日志格式。

    legacy 格式使用 $template 的语法,不过这个在以后要移除,所以最好使用新格式 template():,以免未来突然不工作了也不知道为什么

    模板定义的形式有四种,适用于不同的输出模块,一般简单的格式,可以使用 string 的形式,复杂的格式,建议使用 list 的形式,使用 list 的形式,可以使用一些额外的属性字段(property statement)

    如果不指定输出模板,rsyslog 会默认使用 RSYSLOG_DEFAULT。若想更深入的学习可以查看官方文档

    了解了 rsyslog 环境的配置文件之后,我们看向 /etc/rsyslog.d/50-default.conf 这个配置文件,这个文件中主要是配置的 Filter Conditions,也就是我们在流程图中所看见的 Parser & Filter Engine,它的名字叫 Selectors 是过滤 syslog 的传统方法,他主要由两部分组成,facility 与 priority,其配置格式如下

    facility.priority     log_location

    其中一个 priority 可以指定多个 facility,多个 facility 之间使用逗号 , 分割开

    rsyslog 通过 Facility 的概念来定义日志消息的来源,以便对日志进行分类,Facility 的种类有:

    类别

    解释

    kern

    内核消息

    user

    用户信息

    mail

    邮件系统消息

    daemon

    系统服务消息

    auth

    认证系统

    authpriv

    权限系统

    syslog

    日志系统自身消息

    cron

    计划安排

    news

    新闻信息

    local0~7

    由自定义程序使用

    而另外一部分 priority 也称之为 serverity level,除了日志的来源以外,对统一源产生日志消息还需要进行优先级的划分,而优先级的类别有以下几种:

    类别

    解释

    emergency

    系统已经无法使用了

    alert

    必须立即处理的问题

    critical

    很严重了

    error

    错误

    warning

    警告信息

    notice

    系统正常,但是比较重要

    informational

    正常

    debug

    debug的调试信息

    panic

    很严重但是已淘汰不常用

    none

    没有优先级,不记录任何日志消息

    我们来看看系统中的配置

    auth,authpriv.* /var/log/auth.log

    这里的意思是 auth 与 authpriv 的所有优先级的信息全都输出于 /var/log/auth.log 日志中

    而其中有类似于这样的配置信息意思有细微的差别

    kern.* -/var/log/kern.log

    - 代表异步写入,也就是日志写入时不需要等待系统缓存的同步,也就是日志还在内存中缓存也可以继续写入无需等待完全写入硬盘后再写入。通常用于写入数据比较大时使用。

    到此我们对 rsyslog 的配置就有了一定的了解,若想更深入学习模板,队列的高级应用,大家可去查看官网的文档,需要注意的是 rsyslog 每个版本之间差异化比较大,学习之前先查看自己所使用的版本,再去查看相关的文档

    与日志相关的还有一个还有常用的命令 logger,logger 是一个 shell 命令接口,可以通过该接口使用 Syslog 的系统日志模块,还可以从命令行直接向系统日志文件写入信息。

    #首先将syslog启动起来 sudo service rsyslog start #向 syslog 写入数据 ping 127.0.0.1 | logger -it logger_test -p local3.notice & #查看是否有数据写入 sudo tail -f /var/log/syslog

    从图中我们可以看到我们成功的将 ping 的信息写入了 syslog 中,格式也就是使用的 rsyslog 的默认模板

    我们可以通过 man 来查看 logger 的其他用法,

    参数

    内容

    -i

    在每行都记录进程 ID

    -t

    添加 tag 标签

    -p

    设置日志的 facility 与 priority

     

     

    四、转储的日志

    在本地的机器中每天都有成百上千条日志被写入文件中,更别说是我们的服务器,每天都会有数十兆甚至更多的日志信息被写入文件中,如果是这样的话,每天看着我们的日志文件不断的膨胀,那岂不是要占用许多的空间,所以有个叫 logrotate 的东西诞生了。

    logrotate 程序是一个日志文件管理工具。用来把旧的日志文件删除,并创建新的日志文件。我们可以根据日志文件的大小,也可以根据其天数来切割日志、管理日志,这个过程又叫做“转储”。

    大多数 Linux 发行版使用 logrotate 或 newsyslog 对日志进行管理。logrotate 程序不但可以压缩日志文件,减少存储空间,还可以将日志发送到指定 E-mail,方便管理员及时查看日志。

    显而易见,logrotate 是基于 CRON 来运行的,其脚本是 /etc/cron.daily/logrotate;同时我们可以在 /etc/logrotate 中找到其配置文件

    cat /etc/logrotate.conf

    这其中的具体意思是什么呢?

    # see "man logrotate" for details //可以查看帮助文档 # rotate log files weekly weekly //设置每周转储一次(daily、weekly、monthly当然可以使用这些参数每天、星期,月 ) # keep 4 weeks worth of backlogs rotate 4 //最多转储4次 # create new (empty) log files after rotating old ones create //当转储后文件不存在时创建它 # uncomment this if you want your log files compressed compress //通过gzip压缩方式转储(nocompress可以不压缩) # RPM packages drop log rotation information into this directory include /etc/logrotate.d //其他日志文件的转储方式配置文件,包含在该目录下 # no packages own wtmp -- we'll rotate them here /var/log/wtmp { //设置/var/log/wtmp日志文件的转储参数 monthly //每月转储 create 0664 root utmp //转储后文件不存在时创建它,文件所有者为root,所属组为utmp,对应的权限为0664 rotate 1 //最多转储一次 }

    当然在 /etc/logrotate.d/ 中有各项应用的 logrotate 配置,还有更多的配置参数,大家可以使用 man 查看,如按文件大小转储,按当前时间格式命名等等参数配置。

    展开全文
  • linux基础知识学习

    2019-08-24 08:32:28
    虚拟机安装教程:https://blog.csdn.net/qq_41805715/article/details/100026299 CentOS安装教程:... 一. linux是什么?操作系统/应用程序?...linux就是一个操作系统,如window、unix...
  • Linux基础

    2020-07-23 18:36:36
    Linux基础 一、Linux的简介 多任务多用户的操作系统 1.Linux的概述 Linux是基于Unix的开源免费的操作系统,由于系统的稳定性和安全性几乎成为程序代码运行的最佳系统环境。Linux是由Linus Torvalds(林纳斯·托瓦兹...
  • 一、Linux入门概述 1.1 概述 Linux内核最初只是由芬兰人林纳斯·托瓦兹(Linus Torvalds)在赫尔辛基大学上学时出于个人爱好而编写的。 Linux是一套免费使用和自由传播的类Unix操作系统,是一个基于POSIX和UNIX的...
  • Linux基础知识总结

    2018-11-13 19:40:45
    Linux启动过程 启动流程:操作系统-&gt;/boot -&gt; init进程 -&gt; 运行级别 -&gt; /etc/rc.d-&gt;用户登录-&gt;login shell 内核的引导:首先是BIOS开机自检,按照BIOS中设置的启动设备...
  • Linux基础知识总结一

    2018-07-09 17:54:27
    Unix 特点:多用户多任务;命令行界面;简单、通用、高效;设计原则:1)所有的东西都是文件,所以管理简单 2)所有操作系统配置数据都存储在正文文件中 3)每个操作系统命令或应用程序很小,只完成单一功能 4)...
  • 63个Linux基础自测题,超过10个不会的,劝你还是别玩Linux了
  • 最全的linux基础学习视频,千锋教育的Linux视频课程免费下载地址: http://pan.baidu.com/s/1c13ddvE,更多精彩的视频在不断的更新中,OpenStack覆盖了网络、虚拟化、操作系统、服务器等各个方面。它是一个正在开发...
  • 【Linux】Linux基础常用命令1(常用Linux命令的基本使用,Linux终端命令格式)1. 常用Linux命令的基本使用1.1 学习Linux终端命令的原因1.2 常用Linux命令的基本使用1.3 自动补全2. Linux终端命令格式2.1 终端命令...
  • 嵌入式linux基础学习全套精品视频教程 在给大家分享教程之前,首先给大家简要的介绍一下嵌入式linux,嵌入式linux 是将日益流行的Linux操作系统进行裁剪修改,使之能在嵌入式计算机系统上运行的一种操作系统。...
  • 今天给大家分享一个嵌入式Linux基础的全套视频教程,需要的朋友可以看看!   嵌入式Linux作为一个系统学科,具有知识点多,知识难度大,实践操作性强等特点,很多踌躇满志的同学最终倒在了学习嵌入式Linux的道路...
  • Linux 基础命令入门 实操 从当前目录下切换到根目录下 su 或者 su root 创建yibodong命名的文件夹 创建文件夹并查看列表 mkdir yibodong 显示当前路径 pwd 在yibodong命名的文件夹下创建一个文件YBD mkdir -p ...
  • 学习Linux系统的重要性应该不用多说,下面我就对Linux基础知识进行一个全面而又简单的总结。不过建议大家还是装个Linux系统多练习,平时最好只在Linux环境下编程,这样会大有提高。  linux的特点  - 免费的/...
  • Linux基础1 一、题目内容:给你点提示吧:key的格式是KEY{},题目地址:链接: http://pan.baidu.com/s/1skJ6t7R 密码: s7jy 二、在linux操作系统上进入链接,下载文件(或者,在windows上下载后用winscp连接linux...
  • linux面试基础考题

    2016-03-03 12:02:57
    本片文章可能对没什么基础的初学者有些用,大部分有linux基础的童鞋们就请自动略过此节吧-_-|| 而且,学习或者复习linux这个东西,强烈建议不要光看书,一定动手敲一敲,玩一玩,会上手快得多。  linux是一...
1 2 3 4 5 ... 20
收藏数 588,458
精华内容 235,383
关键字:

linux基础