基于Linux命令行与shell脚本编程大全(第3版)

一、初识Linux shell

Linux系统分为4个部分:

  • Linux内核

  • GNU工具

  • 图形化桌面环境

  • 应用软件

Linux系统

Linux内核

内核控制计算机系统上所有硬件和软件。主要有四个功能

  • 系统内存管理:管理服务器可用的物理内存,并且可以创建和管理虚拟内存。内核通过硬盘上的存储空间实现虚拟内存,这块区域称为交换空间。内核不断地在交换空间和实际物理内存之间反复交换虚拟内存的内容,使它拥有比物理内存更多的可用内存。

    内存分成很多块,称为页面。内核将每个内存页面放在物理内存或交换空间。然后,内核会维护一个内存页面表,指明哪些页面位于物理内存中,哪些页面被交换到了磁盘上。内核会记录哪些内存页面正在使用中,并自动把一段时间未访问的内存页面复制到交换空间区域(称为换出)——即使还有可用内存。当程序要访问一个已被换出的内存页面时,内核必须从物理内存换出另外一个内存页面给它让出空间,然后从交换空间换入请求的内存页面。

  • 软件程序管理:Linux将运行的程序称为进程。内核创建了第一个进程(称为init进程)来启动系统上所有其他进程。当内核启动时,它会将init进程加载到虚拟内存中。内核在启动任何其他进程时,都会在虚拟内存中给新进程分配一块专有区域来存储该进程用到的数据和代码。

  • 硬件设备管理:内核模块。它允许将驱动代码插入到运行中的内核而无需重新编译内核。同时,当设备不再使用时也可将内核模块从内核中移走。
    Linux系统将硬件设备当成特殊的文件,称为设备文件。设备文件有3种分类:字符型设备文件、
    块设备文件、网络设备文件

  • 文件系统管理:Linux内核支持通过不同类型的文件系统从硬盘中读写数据。除了自有的诸多文件系统外,Linux还支持从其他操作系统(比如Microsoft Windows)采用的文件系统中读写数据。内核必须在编译时就加入对所有可能用到的文件系统的支持。

GNU工具

操作系统需要工具来执行一些标准功能,如控制软件和程序。

1.核心GNU工具

  • 处理文件的工具
  • 操作文本的工具
  • 管理进程的工具

2.shell

GNU/Linux shell是一种特殊的交互式工具。shell的核心是命令行提示符。命令行提示符是shell负责交互的部分。它允许你输人文本命令,然后解释命令,并在内核中执行。
shell包含了一组内部命令,用这些命令可以完成诸如复制文件、移动文件、重命名文件、显示和终止系统中正运行的程序等操作。shell也允许你在命令行提示符中输人程序的名称,它会将程序名传递给内核以启动它。
你也可以将多个shell命令放入文件中作为程序执行。这些文件被称作shell脚本。你在命令行上执行的任何命令都可放进一个shell脚本中作为一组命令执行。这为创建那种需要把几个命令放在一起来工作的工具提供了便利。

二、bash shell命令

man命令访问Linux的手册页面

Linux的文件系统

Linux将文件存储在单个目录结构中,这个目录被称为虚拟目录( virtual directory )。虚拟目录将安装在PC上的所有存储设备的文件路径纳入单个目录结构中。
Linux虚拟目录结构只包含一个称为根(root)目录的基础目录。根目录下的目录和文件会按照访问它们的目录路径一一列出,这点跟Windows类似。

Linux使用正斜线(/)而不是反斜线(\)在文件路径中划分目录。在Linux中,反斜线用来标识转义字符,要是用在文件路径中的话会导致各种各样的问题。

Linux虚拟目录中比较复杂的部分是它如何协调管理各个存储设备。在Linux PC上安装的第一块硬盘称为根驱动器。根驱动器包含了虚拟目录的核心,其他目录都是从那里开始构建的。
Linux会在根驱动器上创建一些特别的目录,我们称之为挂载点(mount point)。挂载点是虚拟目录中用于分配额外存储设备的目录。虚拟目录会让文件和目录出现在这些挂载点目录中,然而实际上它们却存储在另外一个驱动器中。

通常系统文件会存储在根驱动器中,而用户文件则存储在另一驱动器中

Linux文件结构
目录 用途
/ 虚拟目录的根目录。通常不会在这里存储文件
/bin 二进制目录,存放许多用户级的GNU工具
/boot 启动目录,存放启动文件
/dev 设备目录,Linux在这里创建设备节点
/etc 系统配置文件目录
/home 主目录,Linux在这里创建用户目录
/lib 库目录,存放系统和应用程序的库文件
/media 媒体目录,可移动媒体设备的常用挂载点
/mnt 挂载目录,另一个可移动媒体设备的常用挂载点
/opt 可选目录,常用于存放第三方软件包和数据文件
/proc 进程目录,存放现有硬件及当前进程的相关信息
/root root用户的主目录
/sbin 系统二进制目录,存放许多GNU管理员级工具
/run 运行目录,存放系统运作时的运行时数据
/srv 服务目录,存放本地服务的相关文件
/sys 系统目录,存放系统硬件信息的相关文件
/tmp 临时目录,可以在该目录中创建和删除临时工作文件
/usr 用户二进制目录,大量用户级的GNU工具和数据文件都存储在这里
/var 可变目录,用以存放经常变化的文件,比如日志文件

命令

查看文件

  1. cat 显示文件所有数据
    • -n 给所有行家行号
    • -b 只给文本加行号
  2. more 显示文本文件的内容,但会在每页数据之后停下来。
  3. less命令实现文本的前后翻动,和高级搜索。
  4. tail 查看文件的尾部,默认显示10行
    • tail -n 2 file 修改所显示的行号
    • tail -100f file 可以在其他进程使用该文件时查看文件的内容,实时检测日志。
  5. head 显示文件开头行的内容 默认10行

监测程序

  1. ps命令 查看进程的信息。默认情况下,ps命令只会显示运行在当前控制台下的属于当前用户的进程。如果想显示所有的进 -ef

    • -e 显示所有进程

    • -f 显示完整格式输出,格式如下

      标题 作用
      UID 启动这些进程的用户
      PID 进程的进程ID
      PPID 父进程的进程号(如果该进程是由另一个进程启动的)
      C 进程生命周期中的CPU利用率。
      STIME 进程启动时的系统时间
      TTY 进程启动时的终端设备
      TIME 运行进程需要的累计CPU时间
      CMD 启动的程序名称
  2. top 实时检测进程。

    第一行显示了当前时间、系统的运行时间、登录的用户数以及系统的平均负载。

    第二行显示了进程概要信息——top命令的输出中将进程叫作任务(task):有多少进程处在运行、休眠、停止或是僵化状态

    第三行显示了CPU的概要信息。top根据进程的属主(用户还是系统)和进程的状态(运行、空闲还是等待)将CPU利用率分成几类输出。

    紧跟其后的两行说明了系统内存的状态。第一行说的是系统的物理内存:总共有多少内存,当前用了多少,还有多少空闲。后一行说的是同样的信息,不过是针对系统交换空间(如果分配了的话)的状态而言的。

    最后一部分显示了当前运行中的进程的详细列表

  3. kill 命令通过进程ID给进程发信号。默认会发生一个TREN信号(尽可能终止)。如果需要无条件终止,则需要添加 -9参数

检测磁盘空间

  1. mount 挂载存储媒体,输出当前系统上挂载的设备列表。

    展示4个部分的信息

    • 媒体的设备文件名
    • 媒体挂载到虚拟目录的挂载点
    • 文件系统类型
    • 已挂载媒体的访问状态

    mount -t type device directory手动挂载设备

    如果是和window公用的存储一般有以下几种

    • vfat: windows长文件系统,大多数U盘和软件的格式
    • ntfs: window广泛使用的高级文件系统
    • iso9660: 标准CD-ROM文件系统
  2. umount卸载设备

    umount [ directory |device] 如果正在使用中,就不会被卸载

    如果在卸载设备时,显示设备繁忙,可以通过

    lsof dir 获取使用它的进程信息,然后在应用中停止使用该设备或停止该进程。

  3. df 查看设备还有多少磁盘空间

    -h 会展现为用户易读的形式 会用M或G代表磁盘

  4. du 显示某个特定目录的磁盘使用情况,默认显示当前目录下所有文件

    • -c显示所有已列出文件的大小
    • -h按用户易读的格式输出大小
    • -s显示每个输出参数的总计

处理数据文件

  1. sort 排序 ,默认按照语言的排序规则对文本文件中数据进行排序

    • -n 可以按照值的大小进排序
    • -r 反序排序
    • -M 识别月份
    • -t 指定分隔符
    • -k知道你个排序字段
  2. grep 搜索指令

    grep [options] pattern [file] 会在输入或指定文件中查找匹配指定模式的字符的行

    • -v 反向搜索,输出不匹配的行
    • -n 行号
    • -c 有多少匹配的
    • -e 多个匹配模式

    并且可以使用正则表达式进行匹配。

    除此之外还有egrep支持更多的匹配模式 和fgrep支持将匹配模式指定为用换行符分割的一列固定长度的字符串。这样就可以把这列字符串放到一个文件中。

  3. 压缩数据

    工 具 文件扩展名 描 述
    bzip2 .bz2 采用Burrows-Wheeler块排序文本压缩算法和霍夫曼编码
    gzip .gz GNU压缩工具,用Lempel-Ziv编码
    zip .zip Windows上PKZIP工具的Unix实现

    gzip是Linux上最流行的压缩工具。

    • gzip:用来压缩文件。
    • gzcat:用来查看压缩过的文本文件的内容。
    • gunzip:用来解压文件。
  4. tar 归档数据,将数据压缩和归档进单个文件

    tar function [options] object1 object2

    function

    功 能 描 述
    -A 将一个已有tar归档文件追加到另一个已有tar归档文件
    -c 创建一个新的tar归档文件
    -d 检查归档文件和文件系统的不同之处
    -r 追加文件到已有tar归档文件末尾
    -t 列出已有tar归档文件的内容
    -u 将比tar归档文件中已有的同名文件新的文件追加到该tar归档文件中
    -x 从已有tar归档文件中提取文件

    每个功能可以用选项来针对tar归档文件定义一个特定行为

    选项 描述
    -C dir 切换到指定目录
    -f file 输出结果到文件或设备
    -j 将输出重定向给bzip2命令来压缩内容
    -p 保留所有文件权限
    -v 在处理文件时显示文件
    -z 将输出重定向给gzip命令来压缩内容
    • 压缩文件

      1
      tar -czvf filename.tar.gz file

      c表示创建一个tar归档文件,z表示tar包用gzip压缩用gunzip解压,v显示详细信息,f选择文件

    • 解压文件

      1
      tar -zxvf filename.tar.gz

      z表示tar包用gzip压缩用gunzip解压, x提取文件,v显示详细信息,f选择文件

三、理解shell

shell不单单是一种CLI,是一个时刻都在运行的复杂交互式程序。

shell类型

启动什么shell取决于个人用户的ID配置,在/etc/passwd中第7个字段列出了默认是hell程序。

bash shell位于/bin/bash目录中,是一个可执行程序。

还有一个默认的sh是/bin/sh 作为默认系统的shell

shell 的父子关系

登陆时启动的shell是一个父shell,而在CLI提示符中输入/bin/bash或其他shell命令时,会创建一个新的shell程序,是一个子shell。

ps -f可以帮助我们看到shell程序

进程就是正在运行的程序。bash shell是一个程序,当它运行的时候,就成为了一个进程。一个运行着的shell就是某种进程而已。因此,在说到运行一个bash shell的时候,你经常会看到“shell”和“进程”这两个词交换使用。

在生成子shell进程时,只有部分父进程的环境被复制到子shell环境中。这会对包括变量在内的一些东西造成影响。

exit可以帮助我们退出这些shell

进程列表

可以在一行指定要依次运行的一系列命令。这可以通过命令列表来实现。在每个命令之间加入;

1
pwd; ls; cd /etc;

加入括号可以使之成为进程列表

1
(pwd ; ls ; cd /etc ;)

括号的加入使命令列表变成了进程列表,生成了一个子shell来执行对应的命令。

其他shell用法

在交互式的shell CLI中,进程列表、协程和管道都利用了子shell。它们都可以有效地在交互式shell中使用。

  1. 后台模式:在后台模式中运行命令可以在处理命令的同时让出CLI,以供他用。

    1
    sleep 10		

    让进程睡眠10s,会让会话暂停10s,然后返回shell CLI

    1
    sleep 10&

    在命令末尾加入&就可以将命令置入后台模式。这个命令执行时会返回2条信息,1条是后台作业号,2是后台作业进程ID。

    jobs用来显示后台作业信息 Running表示当前正在运行,Done表示运行结束。

  2. 将进程列表置入后台

    1
    (sleep 2 ; echo $BASH_SUBSHELL ; sleep 2)

    将进程列表置入后台模式,你既可以在子shell中进行繁重的处理工作,同时也不会让子shell的I/O受制于终端。

  3. 协程:协程可以同时做两件事。它在后台生成一个子shell,并在这个子shell中执行命令。

    coproc命令

    1
    coproc my_job { sleep 10; }

    除了会创建子shell之外,协程基本上就是将命令置入后台模式。通过使用扩展语法,协程的名字被设置成My_Job。必须确保在第一个花括号({)和命令名之间有一个空格。还必须保证命令以分号(;)结尾。

shell内建命令

外部命令

外部命令(文件系统命令)存在于bash shell之外的程序。它们并不是shell程序的一部分。外部命令程序通常位于/bin、/usr/bin、/sbin或/usr/sbin中。

ps就是一个外部命令。

1
2
3
4
5
$ which ps
/bin/ps

$ type -a ps
ps is /bin/ps

当外部命令执行时,会创建出一个子进程。这种操作被称为衍生(forking)。外部命令ps很方便显示出它的父进程以及自己所对应的衍生子进程。作为外部命令,ps命令执行时会创建出一个子进程。

外部命令的衍生

内建命令

内建命令和外部命令的区别在于前者不需要使用子进程来执行。它们已经和shell编译成了一体,作为shell工具的组成部分存在。不需要借助外部程序文件来运行。

1
2
3
4
5
6
$ type cd 
cd is a shell builtin
$
$ type exit
exit is a shell builtin
$

内建命令的执行速度要更快,效率也更高。

有些命令有多种实现。例如echo和pwd既有内建命令也有外部命令。两种实现略有不同。要查看命令的不同实现,使用type -a选项,显示出了每个命令的两种实现,which`命令只显示出了外部命令文件。

  1. history命令跟踪你用过的命令,通常会保留最近的1000条命令

    你可以唤回并重用历史列表中最近的命令。这样能够节省时间和击键量。输入!!,就能够唤出刚刚用过的那条命令来使用。

    bash命令的历史记录是先存放在内存中,当shell退出时才被写入到历史文件中。

    history -a 实现强制写入。

    如果打开了多个终端会话,仍然可以使用history -a命令在打开的会话中向.bash_history文件中添加记录。但是对于其他打开的终端会话,历史记录并不会自动更新。这是因为.bash_history文件只有在打开首个终端会话时才会被读取。要想强制重新读取.bash_history文件,更新终端会话的历史记录,可以使用history -n命令。

    !编号就可以执行命令

  2. alias 命令别名

    alias -p 查看当前可用的别名。

    alias li='ls -li' 随时都可以在shell中使用它,就算在shell脚本中也没问题,仅在它所被定义的shell进程中才有效

四、Linux环境变量

bash shell用一个叫作环境变量(environment variable)的特性来存储有关shell会话和工作环境的信息。这项特性允许你在内存中存储数据,以便程序或shell中运行的脚本能够轻松访问到它们。

环境变量

全局环境变量

全局环境变量对于shell会话和所有生成的子shell都是可见。局部变量则只对创建它们的shell可见。

查看全局变量envprintenv,printenv还可以输出名字

1
2
 printenv HOME
/root

局部环境变量

尽管它们是局部的,但是和全局环境变量一样重要。也可以定义自己的局部变量,这些变量被称为用户定义局部变量。

set命令会显示为某个特定进程设置的所有环境变量,包括局部变量、全局变量以及用户定义变量。

set命令会显示出全局变量、局部变量以及用户定义变量。它还会按照字母顺序对结果进行排序。env和printenv命令同set命令的区别在于前两个命令不会对变量排序,也不会输出局部变量和用户定义变量。在这种情况下,env和printenv的输出是重复的。不过env命令有一个printenv没有的功能,这使得它要更有用一些。

设置用户定义变量

设置局部用户定义变量

可以通过等号给环境变量赋值,值可以是数值或字符串。

1
2
3
4
5
6
echo $my_variable 

my_variable=Hello

echo $my_variable
Hello

所有的环境变量名均使用大写字母,这是bash shell的标准惯例。如果是你自己创建的局部变量或是shell脚本,请使用小写字母。

变量名、等号和值之间没有空格,如果在赋值表达式中加上了空格,bash shell就会把值当成一个单独的命令

设置全局环境变量

通过export命令来创建,变量名前面不需要加$。

1
2
3
4
5
6
7
my_variable="I am Global now" 

export my_variable

echo $my_variable
I am Global now

修改子shell中全局环境变量并不会影响到父shell中该变量的值。

子shell甚至无法使用export命令改变父shell中全局环境变量的值。

删除环境变量

unset命令删除,不要使用$。

1
2
3
4
5
echo $my_variable 
I am Global now

unset my_variable

如果要用到变量,使用$;如果要操作变量,不使用$。这条规则的一个例外就是使用printenv显示某个变量的值。

设置 PATH 环境变量

当你在shell命令行界面中输入一个外部命令时,shell必须搜索系统来找到对应的程序。PATH环境变量定义了用于进行命令和程序查找的目录。

1
2
echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin

PATH中的目录使用冒号分隔。

把新的搜索目录添加到现有的PATH环境变量中

1
PATH=$PATH:dir

对PATH变量的修改只能持续到退出或重启系统。

定位系统环境变量

如何让环境变量的作用持久化。

登入Linux系统启动一个bash shell时,默认情况下bash会在几个文件中查找命令。这些文件叫作启动文件或环境文件。bash检查的启动文件取决于你启动bash shell的方式。

启动bash shell有3种方式:

  • 登录时作为默认登录shell
  • 作为非登录shell的交互式shell
  • 作为运行脚本的非交互shell

登录 shell

会从5个不同的启动文件读取命令

1
2
3
4
5
/etc/profile 
$HOME/.bash_profile
$HOME/.bashrc
$HOME/.bash_login
$HOME/.profile
  1. /etc/profile文件是系统上默认的bash shell的主启动文件。

    centos的/etc/profile

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    # /etc/profile

    # System wide environment and startup programs, for login setup
    # Functions and aliases go in /etc/bashrc

    # It's NOT a good idea to change this file unless you know what you
    # are doing. It's much better to create a custom.sh shell script in
    # /etc/profile.d/ to make custom changes to your environment, as this
    # will prevent the need for merging in future updates.

    pathmunge () {
    case ":${PATH}:" in
    *:"$1":*)
    ;;
    *)
    if [ "$2" = "after" ] ; then
    PATH=$PATH:$1
    else
    PATH=$1:$PATH
    fi
    esac
    }


    if [ -x /usr/bin/id ]; then
    if [ -z "$EUID" ]; then
    # ksh workaround
    EUID=`/usr/bin/id -u`
    UID=`/usr/bin/id -ru`
    fi
    USER="`/usr/bin/id -un`"
    LOGNAME=$USER
    MAIL="/var/spool/mail/$USER"
    fi

    # Path manipulation
    if [ "$EUID" = "0" ]; then
    pathmunge /usr/sbin
    pathmunge /usr/local/sbin
    else
    pathmunge /usr/local/sbin after
    pathmunge /usr/sbin after
    fi

    HOSTNAME=`/usr/bin/hostname 2>/dev/null`
    if [ "$HISTCONTROL" = "ignorespace" ] ; then
    export HISTCONTROL=ignoreboth
    else
    export HISTCONTROL=ignoredups
    fi

    export PATH USER LOGNAME MAIL HOSTNAME HISTSIZE HISTCONTROL

    # By default, we want umask to get set. This sets it for login shell
    # Current threshold for system reserved uid/gids is 200
    # You could check uidgid reservation validity in
    # /usr/share/doc/setup-*/uidgid file
    if [ $UID -gt 199 ] && [ "`/usr/bin/id -gn`" = "`/usr/bin/id -un`" ]; then
    umask 002
    else
    umask 022
    fi

    for i in /etc/profile.d/*.sh /etc/profile.d/sh.local ; do
    if [ -r "$i" ]; then
    if [ "${-#*i}" != "$-" ]; then
    . "$i"
    else
    . "$i" >/dev/null
    fi
    fi
    done

    unset i
    unset -f pathmunge

    for语句用来迭代/etc/profile.d目录下所有文件。

  2. $HOME目录下的启动文件

    提供一个用户专属的启动文件来定义该用户所用到的环境变量。以每个用户都可以编辑这些文件并添加自己的环境变量,这些环境变量会在每次启动bash shell会话时生效。

交互式 shell 进程

交互式shell启动的,它就不会访问/etc/profile文件,只会检查用户HOME目录中的.bashrc文件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
cat .bashrc
# .bashrc

# User specific aliases and functions

alias rm='rm -i'
alias cp='cp -i'
alias mv='mv -i'

# Source global definitions
if [ -f /etc/bashrc ]; then
. /etc/bashrc
fi

.bashrc文件有两个作用:一是查看/etc目录下通用的bashrc文件,二是为用户提供一个定制自

己的命令别名和私有脚本函数的地方。

非交互式 shell

系统执行shell脚本时用的就是这种shell。

bash shell提供了BASH_ENV环境变量。当shell启动一个非交互式shell进程时,它会检查这个环境变量来查看要执行的启动文件。如果有指定的文件,shell会执行该文件里的命令,这通常包括shell脚本变量设置。

环境变量持久化

将新的或修改过的变量设置放在/etc/profile文件中,如果升级了所用的发行版,这个文件也会跟着更新,最好是在/etc/profile.d目录中创建一个以.sh结尾的文件。把所有新的或修改过的全局环境变量设置放在这个文件中。

数组变量

数组是能够存储多个值的变量。这些值可以单独引用,也可以作为整个数组来引用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
$  mytest=(one two three four five)
$ echo $mytest
one
$ echo ${mytest[2]}
three

# 要显示整个数组变量,可用星号作为通配符放在索引值的位置。
$ echo ${mytest[*]}
one two three four five

#用unset命令删除数组中的某个值
$ unset mytest[2]
#这个位置是空的。
$ echo ${mytest[2]}

$ echo ${mytest[3]}
four

五、Linux文件权限

Linux 的安全性

用户权限是通过创建用户时分配的用户ID(User ID,通常缩写为UID)来跟踪的。UID是数值,每个用户都有唯一的UID,但在登录系统时用的不是UID,而是登录名。

/etc/passwd 文件

Linux系统使用一个专门的文件来将用户的登录名匹配到对应的UID值。这个文件就是/etc/passwd文件,它包含了一些与用户有关的信息。

root用户账户是Linux系统的管理员,固定分配给它的UID是0。Linux系统会为各种各样的功能创建不同的用户账户,而这些账户叫作系统账户,是系统上运行的各种服务进程访问资源用的特殊账户。所有运行在后台的服务都需要用一个系统用户账户登录到Linux系统上。

/etc/passwd文件的字段包含了如下信息

  • 登录用户名
  • 用户密码
  • 用户账户的UID(数字形式)
  • 用户账户的组ID(GID)(数字形式)
  • 用户账户的文本描述(称为备注字段)
  • 用户HOME目录的位置
  • 用户的默认shell

/etc/passwd文件中的密码字段都被设置成了x,现在密码再/etc/shadow中,只有特定的程序(比如登录程序)才能访问这个文件。只有root用户才能访问/etc/shadow文件

用户

  1. useradd添加新用户 -m可以创建home目录

  2. userdel 删除用户,默认删除/etc/passwd文件中的用户信息,而不会删除系统中属于该账户的任何文件。

    • -r 会删除用户的HOME目录以及邮件目录。
  3. 修改用户

    命 令 描 述
    usermod 修改用户账户的字段,还可以指定主要组以及附加组的所属关系
    passwd 修改已有用户的密码
    chpasswd 从文件中读取登录名密码对,并更新密码
    chage 修改密码的过期日期
    chfn 修改用户账户的备注信息
    chsh 修改用户账户的默认登录shell

Linux 组

权限允许多个用户对系统中的对象(比如文件、目录或设备等)共享一组共用的权限。

/etc/group 文件

文件的信息

  • 组名

  • 组密码

  • GID

  • 属于该组的用户列表

不能通过直接修改/etc/group文件来添加用户到一个组,要用usermod命令。

在添加用户到不同的组之前,首先得创建组。

命令

  1. groupadd创建新组,通过usermod -G 把用户添加到该组中
  2. groupmod修改组

文件权限

文件权限符

ls输出的字段

1
2
drwxr-xr-x. 85 root root  4096 Sep 19 21:33 etc
drwxr-xr-x. 2 root root 4096 Apr 11 2018 home

第一个字段描述文件和目录权限的编码。

1
2
3
4
5
6
-代表文件
d代表目录
l代表链接
c代表字符型设备
b代表块设备
n代表网络设备

有3组三字符的编码。每一组定义了3种访问权限:

1
2
3
r代表对象是可读的
w代表对象是可写的
x代表对象是可执行的

3组权限分别对应对象的3个安全级别:

1
2
3
对象的属主
对象的属组
系统其他用户

默认文件权限

umask命令用来设置所创建文件和目录的默认权限。

1
2
$  umask 
0022

第一位代表了一项特别的安全特性,叫作粘着位(sticky bit)。后面的3位表示文件或目录对应的umask八进制值。rwx代表着8进制为111,每一位存在就代表着一位是1。

的umask值是0022,而我所创建的文件的八进制权限却是644?umask值只是个掩码。它会屏蔽掉不想授予该安全级别的权限。对文件来说,全权限的值是666(rw-),而对目录来说,则是777(rwx),文件一开始的权限是666,减去umask值022之后,剩下的文件权限就成了644。

umask值通常会设置在/etc/profile启动文件中

改变安全性

  1. 改变权限 chmod

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    #八进制模式
    chmod options mode file
    chmod 760 file

    #符号模式 u代表用户,g代表组,o代表其他,a代表上述所有
    #X:如果对象是目录或者它已有执行权限,赋予执行权限。
    #s:运行时重新设置UID或GID。
    #t:保留文件或目录。
    #u:将权限设置为跟属主一样。
    #g:将权限设置为跟属组一样。
    #o:将权限设置为跟其他用户一样。
    [ugoa…][[+-=][rwxXstugo…]
    chmod o+r file
  2. 改变所属关系 chown

    1
    2
    3
    4
    5
    6
    chown options owner[.group] file
    #可用登录名或UID来指定文件的新属主
    chown dan newfile

    #支持同时改变文件的属主和属组。
    chown dan.shared newfile
    • -R选项配合通配符可以递归地改变子目录和文件的所属关系。

    • -h选项可以改变该文件的所有符号链接文件的所属关系。

共享文件

Linux为每个文件和目录存储了3个额外的信息位。

  • 设置用户ID(SUID):当文件被用户使用时,程序会以文件属主的权限运行。
  • 设置组ID(SGID):对文件来说,程序会以文件属组的权限运行;对目录来说,目录中创建的新文件会以目录的默认属组作为默认属组。
  • 粘着位:进程结束后文件还驻留(粘着)在内存中。

SGID位对文件共享非常重要。启用SGID位后,你可以强制在一个共享目录下创建的新文件都属于该目录的属组,这个组也就成为了每个用户的属组。

要创建一个共享目录,使目录里的新文件都能沿用目录的属组,只需将该目录的SGID位置位。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
$  mkdir testdir 
$ ls -l
drwxrwxr-x 2 rich rich 4096 Sep 20 23:12 testdir/
#将目录的默认属组改为包含所有需要共享文件的用户的组
$ chgrp shared testdir
#将目录的SGID位 置位,以保证目录中新建文件都用shared作为默认属组。
$ chmod g+s testdir
$ ls -l
drwxrwsr-x 2 rich shared 4096 Sep 20 23:12 testdir/
#所有组成员都需把他们的umask值设置成文件对属组成员可写。
$ umask 002
$ cd testdir
$ touch testfile
$ ls -l
total 0
-rw-rw-r-- 1 rich shared 0 Sep 20 23:13 testfile

六、管理文件系统

Linux的文件系统

Linux支持多种类型的文件系统管理文件和目录。每种文件系统都在存储设备上实现了虚拟目录结构。

1.基本Linux文件系统

  1. ext文件系统 ,扩展文件系统(extended filesystem),使用虚拟目录来操作硬件设备,在物理设备上按定长的块来存储数据。

    ext文件系统采用名为索引节点的系统来存放虚拟目录中所存储文件的信息。索引节点系统在每个物理设备中创建一个单独的表(称为索引节点表)来存储这些文件的信息。存储在虚拟目录中的每一个文件在索引节点表中都有一个条目。ext文件系统名称中的extended部分来自其跟踪的每个文件的额外数据。

    1
    2
    3
    4
    5
    6
    文件名
    文件大小
    文件的属主
    文件的属组
    文件的访问权限
    指向存有文件数据的每个硬盘块的指针
  2. ext2文件系统:是ext文件系统基本功能的一个扩展。

    • 为文件添加了创建时间值、修改时间值和最后访问时间值来帮助系统管理员追踪文件的访问情况。
    • 改变了文件在数据块中存储的方式。统通过按组分配磁盘块来减轻碎片化。通过将数据块分组,文件系统在读取文件时不需要为了数据块查找整个物理设备。

    索引节点表虽然支持文件系统保存有关文件的更多信息,但会对系统造成致命的问题。文件系统每次存储或更新文件,它都要用新信息来更新索引节点表。

2.日志文件系统

不再使用之前先将数据直接写入存储设备再更新索引节点表的做法,而是先将文件的更改写入到临时文件(称作日志,journal)中。在数据成功写到存储设备和索引节点表之后,再删除对应的日志条目。有3种广泛使用的日志方法:

方 法 描 述
数据模式 索引节点和文件都会被写入日志;丢失数据风险低,但性能差
有序模式 只有索引节点数据会被写入日志,但只有数据成功写入后才删除;在性能和安全性之间取得了良好的折中
回写模式 只有索引节点数据会被写入日志,但不控制文件数据何时写入;丢失数据风险高,但仍比不用日志好
  1. ext3文件系统:给每个存储设备增加了一个日志文件,以将准备写入存储设备的数据先记入日志。统用有序模式的日志功能——只将索引节点信息写入日志文件,直到数据块都被成功写入存储设备才删除。

    ext3文件系统为Linux文件系统添加了基本的日志功能,但ext3文件系统无法恢复误删的文件,它没有任何内建的数据压缩功能(虽然有个需单独安装的补丁支持这个功能),ext3文件系统也不支持加密文件。

  2. ext4文件系统:是大多数流行的Linux发行版采用的默认文件系统。支持数据压缩和加密,还支持一个称作区段(extent)的特性。区段在存储设备上按块分配空间,但在索引节点表中只保存起始块的位置。由于无需列出所有用来存储文件中数据的数据块,它可以在索引节点表中节省一些空间。

    ext4还引入了块预分配技术(block preallocation)。如果你想在存储设备上给一个你知道要变大的文件预留空间,ext4文件系统可以为文件分配所有需要用到的块,而不仅仅是那些现在已经用到的块。ext4文件系统用0填满预留的数据块,不会将它们分配给其他文件。

3.写时复制文件系统

日志式技术,你就必须在安全性和性能之间做出选择。尽管数据模式日志提供了最高的安全性,但是会对性能带来影响,因为索引节点和数据都需要被日志化。如果是回写模式日志,性能倒是可以接受,但安全性就会受到损害。

日志式的另一种选择是一种叫作写时复制(copy-on-write,COW)的技术。COW利用快照兼顾了安全性和性能。如果要修改数据,会使用克隆或可写快照。修改过的数据并不会直接覆盖当前数据,而是被放入文件系统中的另一个位置上。即便是数据修改已经完成,之前的旧数据也不会被重写。

操作文件系统

1.创建分区

必须在存储设备上创建分区来容纳文件系统。分区可以是整个硬盘,也可以是部分硬盘,以容纳虚拟目录的一部分。

fdisk工具用来帮助管理安装在系统上的任何存储设备上的分区。必须指定要分区的存储设备的设备名,另外还得有超级用户权限。

创建新磁盘分区最麻烦的事情就是找出安装在Linux系统中的物理磁盘。Linux采用了一种标准格式来为硬盘分配设备名称。对于老式的IDE驱动器,Linux使用的是/dev/hdx。其中x表示一个字母,具体是什么要根据驱动器的检测顺序(第一个驱动器是a,第二个驱动器是b,以此类推)。对于较新的SATA驱动器和SCSI驱动器,Linux使用/dev/sdx。其中的x具体是什么也要根据驱动器的检测顺序(和之前一样,第一个驱动器是a,第二个驱动器是b,以此类推)。

fdisk交互式命令提示符使用单字母命令来告诉fdisk做什么。

  • p : 输出存储设备的详细信息

  • n:在存储设备上创建新的分区

    分区可以按主分区(primary partition)或扩展分区(extended partition)创建。主分区可以被文件系统直接格式化,而扩展分区则只能容纳其他主分区。扩展分区出现的原因是每个存储设备上只能有4个分区。可以通过创建多个扩展分区,然后在扩展分区内创建主分区进行扩展。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    Command (m for help): n 
    Command action
    e extended
    p primary partition (1-4)
    p
    #在存储设备上给它分配了分区号1
    Partition number (1-4): 1
    #然后给它分配了2 GB的存储设备空间。
    First cylinder (1-652, default 1): 1
    Last cylinder, +cylinders or +size{K,M,G} (1-652, default 652): +2G
  • w: 创建了想要的分区之后,用w命令将更改保存到存储设备上。

2.创建文件系统

将数据存储到分区之前,你必须用某种文件系统对其进行格式化。

工具 用 途
mkfs.ext4 创建一个ext4文件系统
mkreiserfs 创建一个ReiserFS文件系统
mkfs.xfs 创建一个XFS文件系统
mkfs.zfs 创建一个ZFS文件系统
mkfs.btrfs 创建一个Btrfs文件系统
1
2
3
4
#查看是否存在
$ type mkfs.ext4

$ mkfs.ext4 /dev/sdb1

为分区创建了文件系统之后,下一步是将它挂载到虚拟目录下的某个挂载点,这样就可以将数据存储在新文件系统中了。可以将新文件系统挂载到虚拟目录中需要额外空间的任何位置。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
$ 	ls /mnt 
$
#在虚拟目录中创建了挂载点
$ sudo mkdir /mnt/my_partition
$
$ ls -al /mnt/my_partition/
$
$ ls -dF /mnt/my_partition
/mnt/my_partition/
$
#mount命令将新的硬盘分区添加到挂载点。mount命令的-t选项指明了要挂载的文件系统类型(ext4)。
$ sudo mount -t ext4 /dev/sdb1 /mnt/my_partition
$
$ ls -al /mnt/my_partition/
total 24
drwxr-xr-x. 3 root root 4096 Jun 11 09:53 .
drwxr-xr-x. 3 root root 4096 Jun 11 09:58 ..
drwx------. 2 root root 16384 Jun 11 09:53 lost+found

这种方法只能临时挂载文件系统。当重启Linux系统时,文件系统并不会自动挂载。要强制Linux在启动时自动挂载新的文件系统,可以将其添加到/etc/fstab文件。

3.文件系统的检查与修复

fsck命令能够检查和修复大部分类型的Linux文件系统

1
fsck options filesystem

fsck命令使用/etc/fstab文件来自动决定正常挂载到系统上的存储设备的文件系统。用-t命令行选项来指定文件系统类型。

逻辑卷管理

只能在同一个物理硬盘的可用空间范围内调整分区大小。如果硬盘上没有地方了,就必须弄一个更大的硬盘。这时候可以通过将另外一个硬盘上的分区加入已有文件系统,动态地添加存储空间。Linux逻辑卷管理器(logical volume manager,LVM)软件包正好可以用来做这个。它可以让你在无需重建整个文件系统的情况下,轻松地管理磁盘空间。

1.逻辑卷管理布局

逻辑卷管理的核心在于如何处理安装在系统上的硬盘分区。在逻辑卷管理的世界里,硬盘称作物理卷(physical volume,PV)。每个物理卷都会映射到硬盘上特定的物理分区。

多个物理卷集中在一起可以形成一个卷组(volume group,VG)。逻辑卷管理系统将卷组视为一个物理硬盘,但事实上卷组可能是由分布在多个物理硬盘上的多个物理分区组成的。卷组提供了一个创建逻辑分区的平台,而这些逻辑分区则包含了文件系统。

整个结构中的最后一层是逻辑卷(logical volume,LV)。逻辑卷为Linux提供了创建文件系统的分区环境,作用类似于到目前为止我们一直在探讨的Linux中的物理硬盘分区。Linux系统将逻辑卷视为物理分区

可以使用任意一种标准Linux文件系统来格式化逻辑卷,然后再将它加入Linux虚拟目录中的某个挂载点。

image-20210920195802130

横跨了三个不同的物理硬盘,覆盖了五个独立的物理分区。在卷组内部有两个独立的逻辑卷。Linux系统将每个逻辑卷视为一个物理分区。每个逻辑卷可以被格式化成ext4文件系统,然后挂载到虚拟目录中某个特定位置。

通过逻辑卷管理,你随后可以轻松地将这个未使用分区分配到已有卷组:要么用它创建一个新的逻辑卷,要么在需要更多空间时用它来扩展已有的逻辑卷。如果你给系统添加了一块硬盘,逻辑卷管理系统允许你将它添加到已有卷组,为某个已有的卷组创建更多空间,或是创建一个可用来挂载的新逻辑卷。

2.Linux 中的 LVM

允许你在Linux上用简单的命令行命令管理一个完整的逻辑卷管理环境。Linux2.6版本以上采用LVM2。他提供了以下功能。

  1. 快照:允许你在逻辑卷在线的状态下将其复制到另一个设备。传统的备份方法在将文件复制到备份媒体上时通常要将文件锁定。快照允许你在复制的同时,保证运行关键任务的Web服务器或数据库服务器继续工作。
  2. 条带化:可跨多个物理硬盘创建逻辑卷。文件中的数据块会被分散到多个硬盘上。可以将一个文件的多个数据块同时写入多个硬盘,而无需等待单个硬盘移动读写磁头到多个不同位置。
  3. 镜像:镜像是一个实时更新的逻辑卷的完整副本。当你创建镜像逻辑卷时,LVM会将原始逻辑卷同步到镜像副本中。LVM会为文件系统的每次写操作执行两次写入——一次写入到主逻辑卷,一次写入到镜像副本。

3.使用Linux LVM

  1. 定义物理卷

    第一步:将硬盘上的物理分区转换成Linux LVM使用的物理卷区段。fdisk通过t命令改变分区类型。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    Command (m for help): t 
    Selected partition 1
    Hex code (type L to list codes): 8e
    Changed system type of partition 1 to 8e (Linux LVM)

    Command (m for help): p

    Disk /dev/sdb: 5368 MB, 5368709120 bytes
    255 heads, 63 sectors/track, 652 cylinders
    Units = cylinders of 16065 * 512 = 8225280 bytes
    Sector size (logical/physical): 512 bytes / 512 bytes
    I/O size (minimum/optimal): 512 bytes / 512 bytes
    Disk identifier: 0xa8661341

    Device Boot Start End Blocks Id System
    /dev/sdb1 1 262 2104483+ 8e Linux LVM

    Command (m for help): w
    The partition table has been altered!

    Calling ioctl() to re-read partition table.
    Syncing disks.
    $

    第二步:用分区来创建实际的物理卷。pvcreate

    1
    2
    3
    $  sudo pvcreate /dev/sdb1 
    dev_is_mpath: failed to get device for 8:17
    Physical volume "/dev/sdb1" successfully created

    查看创建进度的话,可以使用pvdisplay命令来显示已创建的物理卷列表。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    $  sudo pvdisplay /dev/sdb1 
    "/dev/sdb1" is a new physical volume of "2.01 GiB"
    --- NEW Physical volume ---
    PV Name /dev/sdb1
    VG Name
    PV Size 2.01 GiB
    Allocatable NO
    PE Size 0
    Total PE 0
    Free PE 0
    Allocated PE 0
    PV UUID 0FIuq2-LBod-IOWt-8VeN-tglm-Q2ik-rGU2w7
  2. 创建卷组

    vgcreate创建

    1
    2
    3
    4
    5
    $  sudo vgcreate Vol1 /dev/sdb1 
    Volume group "Vol1" successfully created

    #vgdisplay看新创建的卷组的细节
    $ sudo vgdisplay Vol1

    使用/dev/sdb1分区上创建的物理卷,创建了一个名为Vol1的卷组。

  3. 创建逻辑卷

    统使用逻辑卷来模拟物理分区,并在其中保存文件系统。允许你定义逻辑卷中的文件系统,然后将文件系统挂载到虚拟目录上。lvcreate

    1
    2
    3
    4
    5
    6
    # l指定为逻辑卷指定多少可用的卷组空间,按照卷组空闲空间的百分比来指定这个值。。 -n逻辑卷的名称lvtest
    $ sudo lvcreate -l 100%FREE -n lvtest Vol1
    Logical volume "lvtest" created

    #查看你创建的逻辑卷的详细情况。
    $ sudo lvdisplay Vol1
  4. 创建文件系统

    mkfs.ext4

    1
    2
    3
    4
    5
    6
    7
    $  sudo mkfs.ext4 /dev/Vol1/lvtest

    #令将这个卷挂载到虚拟目录中
    $ sudo mount /dev/Vol1/lvtest /mnt/my_partition
    $
    $ mount
    /dev/mapper/vg_server01-lv_root on / type ext4 (rw)

    注意,mkfs.ext4和mount命令中用到的路径都有点奇怪。路径中使用了卷组名和逻辑卷名,而不是物理分区路径。文件系统被挂载之后,就可以访问虚拟目录中的这块新区域了。

  5. 修改LVM

    于能够动态修改文件系统。

    命 令 功 能
    vgchange 激活和禁用卷组
    vgremove 删除卷组
    vgextend 将物理卷加到卷组中
    vgreduce 从卷组中删除物理卷
    lvextend 增加逻辑卷的大小
    lvreduce 减小逻辑卷的大小

七、安装软件程序

包管理基础

包管理系统(package management system,PMS),软件包存储在服务器上,这些服务器称为仓库(repository)。可以用PMS工具来搜索新的软件包,或者是更新系统上已安装软件包。软件包通常会依赖其他的包,为了前者能够正常运行,被依赖的包必须提前安装在系统中。PMS工具将会检测这些依赖关系,并在安装需要的包之前先安装好所有额外的软件包。

广泛使用的两种主要的PMS基础工具是dpkg和rpm。

Debian(Ubuntu和Linux Mint)使用dpkg会直接和Linux系统上的PMS交互,用来安装、管理和删除软件包。

1
2
3
apt-get 
apt-cache
aptitude

Red Hat的发行版(如Fedora、openSUSE及Mandriva)使用的是rpm命令,该命令是其PMS的底层基础。类似于dpkg命令,rmp命令能够列出已安装包、安装新包和删除已有软件。

1
2
3
yum:在Red Hat和Fedora中使用。
urpm:在Mandriva中使用。
zypper:在openSUSE中使用。

Red Hat的工具

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
$  yum list installed

#重定向到一个文件
$ yum list installed > installed_software

#安装软件
$ yum install package
$ yum install dos2unix.x86_64

#更新软件
#列出所有
$ yum list updates
$ yum update package_name

#卸载软件
#只删除软件包而保留配置文件和数据文件
$ yum remove package_name
#删除所有
$ yum erase package_name

#yum软件仓库
$ yum repolist

安装源码包

将源码包下载到linux上

1
2
3
4
5
6
7
8
9
10
11
# 解压 sysstat提供了各种系统监测工具
tar -zxvf sysstat-11.1.1.tar.gz

#为系统配置,检查依赖关系
./configure

#构建二进制文件
make

#安装
make install

八、编辑器

vi是Unix最初的编辑器。

检查vim软件包

1
2
3
4
5
6
7
$  alias vi 
alias vi='vim'
$
$ which vim
/usr/bin/vim
$
$ ls -l /usr/bin/vim

vim基础

vim编辑器有两种操作模式:

  • 普通模式
  • 插入模式

普通模式的操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#方向操作
h:左移一个字符。
j:下移一行(文本中的下一行)。
k:上移一行(文本中的上一行)。
l:右移一个字符。

#提高移动速度的命令。
PageDown(或Ctrl+F):下翻一屏。
PageUp(或Ctrl+B):上翻一屏。
G:移到缓冲区的最后一行。
num G:移动到缓冲区中的第num行。
gg:移到缓冲区的第一行。

#命令行模式。

编辑数据

1
2
3
4
5
6
7
8
9
10
x 删除当前光标所在位置的字符
dd 删除当前光标所在行
dw 删除当前光标所在位置的单词
d$ 删除当前光标所在位置至行尾的内容
J 删除当前光标所在行行尾的换行符(拼接行)
u 撤销前一编辑命令
a 在当前光标后追加数据
A 在当前光标所在行行尾追加数据
r char 用char替换当前光标所在位置的单个字符
R text 用text覆盖当前光标所在位置的数据,直到按下ESC键

复制和粘贴

vim在删除数据时,实际上会将数据保存在单独的一个寄存器中。可以用p命令取回数据。

1
2
3
4
p 粘贴
y 复制
yw 复制第一个单词
y$ 复制到行尾

可视模式会在你移动光标时高亮显示文本。移动光标到要开始复制的位置,并按下v键。你会注意到光标所在位置的文本已经被高亮显示了。移动光标来覆盖你想要复制的文本(甚至可以向下移动几行来复制更多行的文本)。在移动光标时,vim会高亮显示复制区域的文本。在覆盖了要复制的文本后,按y键来激活复制命令。移动光标到你要放置的位置,使用p命令来粘贴。

查找和替换

按下斜线(/)键。光标会跑到消息行。

替换命令的格式是:

1
2
3
4
5
:s/old/new/ 会跳到old第一次出现的地方,并用new来替换
:s/old/new/g:一行命令替换所有old。
:n,ms/old/new/g:替换行号n和m之间所有old。
:%s/old/new/g:替换整个文件中的所有old。
:%s/old/new/gc:替换整个文件中的所有old,但在每次出现时提示。