走进 Linux shell (三)

走进 Linux shell (二)

7. 理解 Linux 文件权限

Linux 沿用了 Unix 文件权限的办法,即允许用户和组根据每个文件和目录的安全性设置来访问文件。

 

7.1 Linux 的安全性

Linux 安全系统的核心是用户账户。每个能进入 Linux 系统的用户都会被分配唯一的用户账户。用户对系统中各种对象的访问权限取决于他们登录系统时用
的账户。

用户权限是通过创建用户时分配的用户 ID(User ID,通常缩写为UID)来跟踪的。UID 是数值,每个用户都有唯一的 UID,但在登录系统时用的不是 UID,
而是登录名。登录名是用户用来登录系统的最长八字符的字符串(字符可以是数字或字母),同时会关联一个对应的密码。

Linux 系统使用特定的文件和工具来跟踪和管理系统上的用户账户。


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

    [devalone@devalone ~]$ cat /etc/passwd
    root:x:0:0:root:/root:/bin/bash
    bin:x:1:1:bin:/bin:/sbin/nologin
    daemon:x:2:2:daemon:/sbin:/sbin/nologin
    adm:x:3:4:adm:/var/adm:/sbin/nologin
    lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
    sync:x:5:0:sync:/sbin:/bin/sync
    shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
    halt:x:7:0:halt:/sbin:/sbin/halt
    mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
    devalone:x:1000:1000:MichaelY.:/home/devalone:/bin/bash

    ...

root 用户账户是 Linux 系统的管理员,固定分配给它的 UID 是 0。

Linux 系统会为各种各样的功能创建不同的用户账户,而这些账户并不是真的用户。这些账户叫作系统账户,是系统上运行的各种服务进程访问资源用的
特殊账户。所有运行在后台的服务都需要用一个系统用户账户登录到 Linux 系统上。

Linux 为系统账户预留了 500 以下的 UID 值。有些服务甚至要用特定的 UID 才能正常工作。为普通用户创建账户时,大多数 Linux 系统会从 500 开始。
CentOS 7 从 1000 开始用于普通账户。

/etc/passwd 文件的字段包含了如下信息(每一行为一个账户信息,以 : 分隔为 7 个段,分别代表不同的信息):

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

/etc/passwd 文件中的密码字段都被设置成了x,这并不是说所有的用户账户都用相同的密码。现在,绝大多数 Linux 系统都将用户密码保存在另一个单独
的文件中(叫作shadow文件,位于 /etc/shadow)。只有特定的程序(比如登录程序)才能访问这个文件

 

7.1.2 /etc/shadow 文件
-----------------------------------------------------------------------------------------------------------------------------------------
/etc/shadow 文件对 Linux 系统密码管理提供了更多的控制。只有 root 用户才能访问 /etc/shadow 文件,这让它比起 /etc/passwd 安全许多。

    devalone:$6$9rZXEANeschIueWG$KReB.a2J518vAj3YUn9pprEQZABk.sFmQw7oG8UrTwmhzzSJy6vmMckohqSM1P4RSLxs23tHdg8nXHb8OcQoH0::0:99999:7:::

在/etc/shadow文件的每条记录中都有 9 个字段:
    □ 与/etc/passwd 文件中的登录名字段对应的登录名
    □ 加密后的密码
    □ 自上次修改密码后过去的天数密码(自1970年1月1日开始计算)
    □ 多少天后才能更改密码
    □ 多少天后必须更改密码
    □ 密码过期前提前多少天提醒用户更改密码
    □ 密码过期后多少天禁用用户账户
    □ 用户账户被禁用的日期(用自1970年1月1日到当天的天数表示)
    □ 预留字段给将来使用
    
    
使用 shadow 密码系统后,Linux 系统可以更好地控制用户密码。它可以控制用户多久更改一次密码,以及什么时候禁用该用户账户,如果密码未更新的话。


7.1.3 添加新用户
-----------------------------------------------------------------------------------------------------------------------------------------
用来向 Linux 系统添加新用户的主要工具是 useradd。这个命令可以一次性创建新用户账户及设置用户 HOME 目录结构。useradd 命令使用系统的默认值
以及命令行参数来设置用户账户。系统默认值被设置在 /etc/default/useradd 文件中。可以使用加入了-D 选项的 useradd 命令查看所用 Linux 系统中的
这些默认值:

    [devalone@devalone ~]$ cat /etc/default/useradd
    # useradd defaults file
    GROUP=100
    HOME=/home
    INACTIVE=-1
    EXPIRE=
    SHELL=/bin/bash
    SKEL=/etc/skel
    CREATE_MAIL_SPOOL=yes

    [devalone@devalone ~]$ useradd -D
    GROUP=100
    HOME=/home
    INACTIVE=-1
    EXPIRE=
    SHELL=/bin/bash
    SKEL=/etc/skel
    CREATE_MAIL_SPOOL=yes

上述默认值说明:
    □ 新用户会被添加到 GID 为 100 的公共组;
    □ 新用户的 HOME 目录将会位于 /home/loginname;
    □ 新用户账户密码在过期后不会被禁用;
    □ 新用户账户未被设置过期日期;
    □ 新用户账户将 bash shell 作为默认 shell;
    □ 系统会将 /etc/skel 目录下的内容复制到用户的 HOME 目录下;
    □ 系统为该用户账户在 mail 目录下创建一个用于接收邮件的文件。


可以用默认系统参数创建一个新用户账户,然后检查一下新用户的 HOME 目录:

    [root@devalone ~]# useradd -m usertest
    [root@devalone ~]# ll /home/usertest

默认情况下,useradd 命令不会创建 HOME 目录,但是 -m 命令行选项会使其创建 HOME 目录。


    useradd 命令行参数
    +-------------------+-------------------------------------------------------------------------------------------------
    | 参 数                | 描 述
    +-------------------+-------------------------------------------------------------------------------------------------
    | -c comment        | 给新用户添加备注
    +-------------------+-------------------------------------------------------------------------------------------------
    | -d home_dir        | 为主目录指定一个名字(如果不想用登录名作为主目录名的话)
    +-------------------+-------------------------------------------------------------------------------------------------
    | -e expire_date    | 用YYYY-MM-DD格式指定一个账户过期的日期
    +-------------------+-------------------------------------------------------------------------------------------------
    | -f inactive_days    | 指定这个账户密码过期后多少天这个账户被禁用;0 表示密码一过期就立即禁用,1 表示禁用这个功能
    +-------------------+-------------------------------------------------------------------------------------------------
    | -g initial_group    | 指定用户登录组的GID或组名
    +-------------------+-------------------------------------------------------------------------------------------------
    | -G group ...        | 指定用户除登录组之外所属的一个或多个附加组
    +-------------------+-------------------------------------------------------------------------------------------------
    | -k                | 必须和-m一起使用,将/etc/skel目录的内容复制到用户的HOME目录
    +-------------------+-------------------------------------------------------------------------------------------------
    | -m                | 创建用户的HOME目录
    +-------------------+-------------------------------------------------------------------------------------------------
    | -M                | 不创建用户的HOME目录(当默认设置里要求创建时才使用这个选项)
    +-------------------+-------------------------------------------------------------------------------------------------
    | -n                | 创建一个与用户登录名同名的新组
    +-------------------+-------------------------------------------------------------------------------------------------
    | -r                | 创建系统账户
    +-------------------+-------------------------------------------------------------------------------------------------
    | -p passwd            | 为用户账户指定默认密码
    +-------------------+-------------------------------------------------------------------------------------------------
    | -s shell            | 指定默认的登录shell
    +-------------------+-------------------------------------------------------------------------------------------------
    | -u uid            | 为账户指定唯一的UID
    +-------------------+-------------------------------------------------------------------------------------------------

 

    可以在 -D 选项后跟上一个指定的值来修改系统默认的新用户设置:
    +-------------------+-------------------------------------------------------------------------------------------------
    | 参 数                | 描 述
    +-------------------+-------------------------------------------------------------------------------------------------
    | -b default_home    | 更改默认的创建用户HOME目录的位置
    +-------------------+-------------------------------------------------------------------------------------------------
    | -e expiration_date| 更改默认的新账户的过期日期
    +-------------------+-------------------------------------------------------------------------------------------------
    | -f inactive        | 更改默认的新用户从密码过期到账户被禁用的天数
    +-------------------+-------------------------------------------------------------------------------------------------
    | -g group            | 更改默认的组名称或GID
    +-------------------+-------------------------------------------------------------------------------------------------
    | -s shell            | 更改默认的登录shell
    +-------------------+-------------------------------------------------------------------------------------------------
    
    
    
7.1.4 删除用户
-----------------------------------------------------------------------------------------------------------------------------------------
默认情况下,userdel 命令会只删除 /etc/passwd 文件中的用户信息,而不会删除系统中属于该账户的任何文件。
如果加上 -r 参数,userdel 会删除用户的 HOME 目录以及邮件目录。然而,系统上仍可能存有已删除用户的其他文件。这在有些环境中会造成问题。

    [root@devalone ~]# userdel -r usertest
    [root@devalone ~]# ll /home
    总用量 20
    drwx------. 55 devalone devalone  4096 7月   3 14:29 devalone
    drwx------.  2 root     root     16384 3月   9 2017 lost+found

 

7.1.5 修改用户
-----------------------------------------------------------------------------------------------------------------------------------------    
Linux 提供了一些不同的工具来修改已有用户账户的信息,如下表所示:


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


    ■ usermod
    -------------------------------------------------------------------------------------------------------------------------------------
    usermod 命令是用户账户修改工具中最强大的一个。它能用来修改 /etc/passwd文件中的大部分字段,只需用与想修改的字段对应的命令行参数就可以了。
    参数大部分跟 useradd 命令的参数一样(比如,-c 修改备注字段,-e 修改过期日期,-g 修改默认的登录组)。除此之外,还有另外一些可能派上用场
    的选项:
    
        -l 修改用户账户的登录名。
        -L 锁定账户,使用户无法登录。
        -p 修改账户的密码。
        -U 解除锁定,使用户能够登录。

    -L 选项尤其实用。它可以将账户锁定,使用户无法登录,同时无需删除账户和用户的数据。要让账户恢复正常,只要用-U选项就行了。


    ■ passwd 和 chpasswd
    -------------------------------------------------------------------------------------------------------------------------------------
    改变用户密码的一个简便方法就是用 passwd 命令:
    
        [root@devalone ~]# passwd user1
        更改用户 user1 的密码 。
        新的 密码:

    如果只用 passwd 命令,它会改自己的密码。系统上的任何用户都能改自己的密码,但只有 root 用户才有权限改别人的密码。
    
    -e 选项能强制用户下次登录时修改密码。可以先给用户设置一个简单的密码,之后再强制在下次登录时改成他们能记住的更复杂的密码。
    
    如果需要为系统中的大量用户修改密码,chpasswd 命令可以事半功倍。chpasswd 命令能从标准输入自动读取登录名和密码对(由冒号分割)列表,
    给密码加密,然后为用户账户设置。也可以用重定向命令来将含有 userid:passwd 对的文件重定向给该命令:
    
    [root@devalone ~]# chpasswd < users.txt
    
    
    ■ chsh、chfn 和 chage
    -------------------------------------------------------------------------------------------------------------------------------------
    chsh、chfn 和 chage 工具专门用来修改特定的账户信息。
    
    chsh 命令用来快速修改默认的用户登录 shell。使用时必须用 shell 的全路径名作为参数,不能只用 shell 名。
    
        # chsh -s /bin/csh user1
        Changing shell for user1.
        Shell changed.
    
    chfn 命令提供了在 /etc/passwd 文件的备注字段中存储信息的标准方法。chfn 命令会将用于 Unix 的 finger命令的信息存进备注字段,而不是简单地
    存入一些随机文本(比如名字或暱称之类的),或是将备注字段留空。finger 命令可以非常方便地查看 Linux 系统上的用户信息:
        
        [root@devalone ~]# finger devalone
        Login: devalone                         Name: MichaelY.
        Directory: /home/devalone               Shell: /bin/bash
        On since 三 7月  4 09:17 (CST) on pts/0 from 192.168.1.101
        No mail.
        No Plan.
    
    如果在使用 chfn 命令时没有参数,它会向询问要将哪些适合的内容加进备注字段:

        [root@devalone ~]# chfn user1
        正在更改 user1 的 finger 信息。
        名称 []: user1 test
        办公 []: tech
        办公电话 []: 12334456
        住宅电话 []: 22233345


        Finger 信息已更改。

    chage 命令用来帮助管理用户账户的有效期。需要对每个值设置多个参数:
    
        chage命令参数:
        +-------+----------------------------------------------------------
        | 参 数    | 描 述
        +-------+----------------------------------------------------------
        | -d    | 设置上次修改密码到现在的天数
        +-------+----------------------------------------------------------
        | -E    | 设置密码过期的日期
        +-------+----------------------------------------------------------
        | -I    | 设置密码过期到锁定账户的天数
        +-------+----------------------------------------------------------
        | -m    | 设置修改密码之间最少要多少天
        +-------+----------------------------------------------------------
        | -W    | 设置密码过期前多久开始出现提醒信息
        +-------+----------------------------------------------------------
    
    chage 命令的日期值可以用下面两种方式中的任意一种:
        YYYY-MM-DD格式的日期
        代表从1970年1月1日起到该日期天数的数值
    
    
    
7.2 使用 Linux 组
-----------------------------------------------------------------------------------------------------------------------------------------
组权限允许多个用户对系统中的对象(比如文件、目录或设备等)共享一组共用的权限。Linux 发行版在处理默认组的成员关系时略有差异。有些 Linux
发行版会创建一个组,把所有用户都当作这个组的成员。遇到这种情况要特别小心,因为文件很有可能对其他用户也是可读的。有些发行版会为每个用户创建
单独的一个组,这样可以更安全一些。

每个组都有唯一的 GID —— 跟UID类似,在系统上这是个唯一的数值。除了GID,每个组还有唯一的组名。Linux系统上有一些组工具可以创建和管理自己的组。


7.2.1 /etc/group 文件
-----------------------------------------------------------------------------------------------------------------------------------------
与用户账户类似,组信息也保存在系统的一个文件中。/etc/group 文件包含系统上用到的每个组的信息。

    [root@devalone ~]# cat /etc/group
    root:x:0:
    bin:x:1:
    daemon:x:2:
    sys:x:3:
    adm:x:4:
    tty:x:5:
    disk:x:6:
    lp:x:7:
    mem:x:8:
    kmem:x:9:
    wheel:x:10:
    cdrom:x:11:
    mail:x:12:
    devalone:x:1000:
    saned:x:978:
    stapusr:x:156:
    stapsys:x:157:
    stapdev:x:158:
    systemd-coredump:x:977:
    ntp:x:38:
    user1:x:1001:
    ...

和 UID 一样,GID 在分配时也采用了特定的格式。系统账户用的组通常会分配低于 500 的 GID 值,而用户组的 GID 则会从 500 开始分配。/etc/group
文件有4个字段(CentOS 7 从 1000 开始分配 GID):
    □ 组名
    □ 组密码
    □ GID
    □ 属于该组的用户列表

千万不能通过直接修改 /etc/group 文件来添加用户到一个组,要用 usermod 命令。在添加用户到不同的组之前,首先得创建组。
    
    
    
7.2.2 创建新组
-----------------------------------------------------------------------------------------------------------------------------------------
groupadd 命令可在系统上创建新组。

    [root@devalone ~]# groupadd shared
    [root@devalone ~]# tail /etc/group
    saned:x:978:
    stapusr:x:156:
    stapsys:x:157:
    stapdev:x:158:
    systemd-coredump:x:977:
    hudson:x:976:
    gitgroup:x:1003:devalone
    ntp:x:38:
    user1:x:1001:
    shared:x:1004:

在创建新组时,默认没有用户被分配到该组。groupadd 命令没有提供将用户添加到组中的选项,但可以用 usermod 命令来弥补这一点。

    [root@devalone ~]# usermod -G shared user1

    [root@devalone ~]# tail -5 /etc/group
    hudson:x:976:
    gitgroup:x:1003:devalone
    ntp:x:38:
    user1:x:1001:
    shared:x:1004:user1

shared 组现在有一个新成员:user1。usermod 命令的 -G 选项会把这个新组添加到该用户账户的组列表里。

 

7.2.3 修改组
-----------------------------------------------------------------------------------------------------------------------------------------
在 /etc/group 文件中可以看到,需要修改的组信息并不多。groupmod 命令可以修改已有组的GID(加-g选项)或组名(加-n选项)。

    [root@devalone ~]# groupmod -n sharing shared
    [root@devalone ~]# tail /etc/group
    stapusr:x:156:
    stapsys:x:157:
    stapdev:x:158:
    systemd-coredump:x:977:
    hudson:x:976:
    gitgroup:x:1003:devalone
    ntp:x:38:
    user1:x:1001:
    test:x:1002:
    sharing:x:1004:user1

修改组名时,GID 和组成员不会变,只有组名改变。由于所有的安全权限都是基于 GID 的,可以随意改变组名而不会影响文件的安全性。


7.3 理解文件权限
-----------------------------------------------------------------------------------------------------------------------------------------


7.3.1 使用文件权限符
-----------------------------------------------------------------------------------------------------------------------------------------
    [devalone@devalone shell-script]$ ll
    总用量 108
    drwxrwxr-x. 2 devalone devalone 4096 1月   2 2018 12
    drwxrwxr-x. 2 devalone devalone 4096 1月   2 2018 13
    drwxrwxr-x. 2 devalone devalone 4096 1月   7 13:15 14
    drwxrwxr-x. 2 devalone devalone 4096 1月   7 13:15 15
    drwxrwxr-x. 2 devalone devalone 4096 7月   2 19:32 dirsh
    drwxr-xr-x. 2 devalone devalone 4096 7月   2 19:26 network-scripts-zz
    -rwxrwxr-x. 1 devalone devalone  152 1月   2 2018 test1.sh
    -rwxrwxr-x. 1 devalone devalone  123 1月   2 2018 test2.sh
    -rwxrwxr-x. 1 devalone devalone  159 1月   2 2018 test3.sh
    -rwxrwxr-x. 1 devalone devalone  123 1月   2 2018 test4.sh
    -rwxrwxr-x. 1 devalone devalone   68 1月   2 2018 test5.sh
    -rw-rw-r--. 1 devalone devalone   72 7月   2 20:08 testfile

输出结果的第一个字段就是描述文件和目录权限的编码。这个字段的第一个字符代表了对象的类型:
    - 代表文件
    d 代表目录
    l 代表链接
    c 代表字符型设备
    b 代表块设备
    n 代表网络设备

之后有 3 组三字符的编码。每一组定义了 3 种访问权限:
    r 代表对象是可读的
    w 代表对象是可写的
    x 代表对象是可执行的
    
若没有某种权限,在该权限位会出现单连字符 "-" 。这 3 组权限分别对应对象的 3 个安全级别:

    □ 对象的属主
    □ 对象的属组
    □ 系统其他用户


7.3.2 默认文件权限
-----------------------------------------------------------------------------------------------------------------------------------------
这些文件权限从何而来,答案是 umask。umask 命令用来设置所创建文件和目录的默认权限。

    [devalone@devalone shell-script]$ touch newfile
    [devalone@devalone shell-script]$ ls -al newfile
    -rw-r--r--. 1 devalone devalone 0 7月   4 16:16 newfile

touch 命令用分配给我的用户账户的默认权限创建了这个文件。umask 命令可以显示和设置这个默认权限。

    [devalone@devalone shell-script]$ umask
    0022

四位数的第一位代表了一项特别的安全特性,叫作粘着位(sticky bit)。后面的 3 位表示文件或目录对应的 umask 八进制值。

八进制模式的安全性设置先获取这3个 rwx 权限的值,然后将其转换成3位二进制值,用一个八进制值来表示。

    Linux文件权限码:
    +-----------+---------------+-----------+-----------------------
    | 权 限        | 二进制值        | 八进制值    | 描 述
    +-----------+---------------+-----------+-----------------------
    | ---        | 000            | 0            | 没有任何权限
    +-----------+---------------+-----------+-----------------------
    | --x        | 001            | 1            | 只有执行权限
    +-----------+---------------+-----------+-----------------------
    | -w-        | 010            | 2            | 只有写入权限
    +-----------+---------------+-----------+-----------------------
    | -wx        | 011            | 3            | 有写入和执行权限
    +-----------+---------------+-----------+-----------------------
    | r--        | 100            | 4            | 只有读取权限
    +-----------+---------------+-----------+-----------------------
    | r-x        | 101            | 5            | 有读取和执行权限        
    +-----------+---------------+-----------+-----------------------
    | rw-        | 110            | 6            | 有读取和写入权限
    +-----------+---------------+-----------+-----------------------
    | rwx        | 111            | 7            | 有全部权限
    +-----------+---------------+-----------+-----------------------

八进制模式先取得权限的八进制值,然后再把这三组安全级别(属主、属组和其他用户)的八进制值顺序列出。因此,八进制模式的值 664 代表属主和属组
成员都有读取和写入的权限,而其他用户都只有读取权限。

umask值只是个掩码。它会屏蔽掉不想授予该安全级别的权限。要把 umask 值从对象的全权限值中减掉。对文件来说,全权限的值是666(所有用户都有读
和写的权限);而对目录来说,则是777(所有用户都有读、写、执行权限)。

所以在上例中,文件一开始的权限是 666,减去 umask值 022之后,剩下的文件权限就成了 644。


7.4 改变安全性设置
-----------------------------------------------------------------------------------------------------------------------------------------


7.4.1 改变权限
-----------------------------------------------------------------------------------------------------------------------------------------
chmod 命令用来改变文件和目录的安全性设置。该命令的格式如下:

    chmod options mode file

mode 参数可以使用八进制模式或符号模式进行安全性设置。八进制模式设置非常直观,直接用期望赋予文件的标准3位八进制权限码即可。

    [devalone@devalone shell-script]$ chmod 760 newfile
    [devalone@devalone shell-script]$ ls -l newfile
    -rwxrw----. 1 devalone devalone 0 7月   4 16:16 newfile

八进制文件权限会自动应用到指定的文件上。

与通常用到的3组三字符权限字符不同,chmod 命令采用了另一种方法。下面是在符号模式下指定权限的格式:

    [ugoa…][[+-=][rwxXstugo…]

第一组字符定义了权限作用的对象:

    u 代表用户
    g 代表组
    o 代表其他
    a 代表上述所有
    
下一步,后面跟着的符号表示是想在现有权限基础上增加权限(+),还是在现有权限基础上移除权限(),或是将权限设置成后面的值(=)。

最后,第三个符号代表作用到设置上的权限。这个值要比通常的 rwx 多。额外的设置有以下几项:

    X:如果对象是目录或者它已有执行权限,赋予执行权限。
    s:运行时重新设置UID或GID。
    t:保留文件或目录。
    u:将权限设置为跟属主一样。
    g:将权限设置为跟属组一样。
    o:将权限设置为跟其他用户一样。

示例:给其它用户增加读取权限
    [devalone@devalone shell-script]$ ls -l newfile
    -rwxrw----. 1 devalone devalone 0 7月   4 16:16 newfile
    [devalone@devalone shell-script]$ chmod o+r newfile
    [devalone@devalone shell-script]$ ls -l newfile
    -rwxrw-r--. 1 devalone devalone 0 7月   4 16:16 newfile

示例:将属主已有的执行权限移除
    [devalone@devalone shell-script]$ chmod u-x newfile
    [devalone@devalone shell-script]$ ls -l newfile
    -rw-rw-r--. 1 devalone devalone 0 7月   4 16:16 newfile

options 为 chmod 命令提供了另外一些功能。-R 选项可以让权限的改变递归地作用到文件和子目录。可以使用通配符指定多个文件,然后利用一条命令
将权限更改应用到这些文件上。


7.4.2 改变所属关系
-----------------------------------------------------------------------------------------------------------------------------------------
有时需要改变文件的属主,Linux提供了两个命令来实现这个功能:chown 命令用来改变文件的属主,chgrp 命令用来改变文件的默认属组。

chown命令的格式如下:

    chown options owner[:group] file

可用登录名或 UID 来指定文件的新属主:

    [root@devalone shell-script]# chown user1 newfile
    [root@devalone shell-script]# ls -l newfile
    -rw-rw-r--. 1 user1 devalone 0 7月   4 16:16 newfile

chown 命令也支持同时改变文件的属主和属组:
    [root@devalone shell-script]# chown user1:sharing newfile
    [root@devalone shell-script]# ls -l newfile
    -rw-rw-r--. 1 user1 sharing 0 7月   4 16:16 newfile

可以只改变一个目录的默认属组:
    [root@devalone shell-script]# chown :devalone newfile
    [root@devalone shell-script]# ls -l newfile
    -rw-rw-r--. 1 user1 devalone 0 7月   4 16:16 newfile

如果 Linux 系统采用和用户登录名匹配的组名,可以只用一个条目就改变二者。

    [root@devalone shell-script]# chown devalone: newfile
    [root@devalone shell-script]# ls -l newfile
    -rw-rw-r--. 1 devalone devalone 0 7月   4 16:16 newfile

chown 命令采用一些不同的选项参数。-R 选项配合通配符可以递归地改变子目录和文件的所属关系。-h 选项改变该文件的所有符号链接文件的所属关系。

    NOTE:
    -------------------------------------------------------------------------------------------------------------------------------------
    只有 root 用户能够改变文件的属主。任何属主都可以改变文件的属组,但前提是属主必须是原属组和目标属组的成员。

chgrp 命令可以更改文件或目录的默认属组:

    [root@devalone shell-script]# chgrp sharing newfile
    [root@devalone shell-script]# ls -l newfile
    -rw-rw-r--. 1 devalone sharing 0 7月   4 16:16 newfile

用户账户必须是这个文件的属主,除了能够更换属组之外,还得是新组的成员。现在 sharing 组的任意一个成员都可以写这个文件了。这是 Linux 系统
共享文件的一个途径。

 

7.5 共享文件
-----------------------------------------------------------------------------------------------------------------------------------------
inux系统上共享文件的方法是创建组。创建新文件时,Linux 会用登录账户默认的 UID 和 GID 给文件分配权限。想让其他人也能访问文件,要么改变其他
用户所在安全组的访问权限,要么就给文件分配一个包含其他用户的新默认属组。

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

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

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

SGID 可通过 chmod 命令设置。它会加到标准3位八进制值之前(组成4位八进制值),或者在符号模式下用符号s。

如果用的是八进制模式,需要知道这些位的位置,如下表:

    chmod SUID、SGID 和粘着位的八进制值:
    +-----------+-----------+---------------------------------------------------------------
    | 二进制值    | 八进制值    | 描 述
    +-----------+-----------+---------------------------------------------------------------
    | 000        | 0            | 所有位都清零
    +-----------+-----------+---------------------------------------------------------------
    | 001        | 1            | 粘着位置位
    +-----------+-----------+---------------------------------------------------------------
    | 010        | 2            | SGID位置位
    +-----------+-----------+---------------------------------------------------------------
    | 011        | 3            | SGID位和粘着位都置位
    +-----------+-----------+---------------------------------------------------------------
    | 100        | 4            | SUID位置位
    +-----------+-----------+---------------------------------------------------------------
    | 101        | 5            | SUID位和粘着位都置位
    +-----------+-----------+---------------------------------------------------------------
    | 110        | 6            | SUID位和SGID位都置位
    +-----------+-----------+---------------------------------------------------------------
    | 111        | 7            | 所有位都置位
    +-----------+-----------+---------------------------------------------------------------

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

    [root@devalone shell-script]# mkdir testdir
    [root@devalone shell-script]# ll testdir
    总用量 0
    [root@devalone shell-script]# ll -d testdir
    drwxr-xr-x. 2 root root 4096 7月   4 17:10 testdir
    [root@devalone shell-script]# chgrp sharing testdir
    [root@devalone shell-script]# ll -d testdir
    drwxr-xr-x. 2 root sharing 4096 7月   4 17:10 testdir
    [root@devalone shell-script]# chmod g+s testdir
    [root@devalone shell-script]# ll -d testdir
    drwxr-sr-x. 2 root sharing 4096 7月   4 17:10 testdir
    [root@devalone shell-script]# umask 002
    [root@devalone shell-script]# cd testdir
    [root@devalone testdir]# ll
    总用量 0
    [root@devalone testdir]# touch testfile
    [root@devalone testdir]# ll
    总用量 0
    -rw-rw-r--. 1 root sharing 0 7月   4 17:12 testfile

用 mkdir 命令来创建希望共享的目录。然后通过 chgrp 命令将目录的默认属组改为包含所有需要共享文件的用户的组(必须是该组的成员)。最后,将
目录的 SGID 位置位,以保证目录中新建文件都用 sharing 作为默认属组。

为了让这个环境能正常工作,所有组成员都需把他们的 umask 值设置成文件对属组成员可写。umask 改成了002,所以文件对属组是可写的。

做完了这些,组成员就能到共享目录下创建新文件了。跟期望的一样,新文件会沿用目录的属组,而不是用户的默认属组。现在 sharing 组的所有用户都能
访问这个文件了。

 

8. 管理文件系统
-----------------------------------------------------------------------------------------------------------------------------------------
使用 Linux 系统时,需要作出的重大决策之一就是为存储设备选用什么文件系统。

 

8.1 探索Linux 文件系统
-----------------------------------------------------------------------------------------------------------------------------------------
Linux 支持多种类型的文件系统管理文件和目录。每种文件系统都在存储设备上实现了虚拟目录结构,仅特性有所不同。


8.1.1 基本的Linux 文件系统
-----------------------------------------------------------------------------------------------------------------------------------------
Linux 最初采用的是一种简单的文件系统,它模仿了 Unix 文件系统的功能。


    ■ ext 文件系统
    -------------------------------------------------------------------------------------------------------------------------------------
    Linux 操作系统中引入的最早的文件系统叫作扩展文件系统(extended filesystem,简记为ext)。它为 Linux 提供了一个基本的类 Unix文件系统:
    使用虚拟目录来操作硬件设备,在物理设备上按定长的块来存储数据。


    ■ ext2 文件系统
    -------------------------------------------------------------------------------------------------------------------------------------
    最早的 ext 文件系统有不少限制,比如文件大小不得超过 2GB。在 Linux 出现后不久,ext文件系统就升级到了第二代扩展文件系统,叫作 ext2。

    ext2 文件系统是 ext 文件系统基本功能的一个扩展,但保持了同样的结构。ext2 文件系统扩展了索引节点表的格式来保存系统上每个文件的更多信息。
    
    ext2 的索引节点表为文件添加了创建时间值、修改时间值和最后访问时间值来帮助系统管理员追踪文件的访问情况。ext2文件系统还将允许的最大文件
    大小增加到了2 TB(在ext2的后期版本中增加到了32 TB),以容纳数据库服务器中常见的大文件。
    
    除了扩展索引节点表外,ext2 文件系统还改变了文件在数据块中存储的方式。ext 文件系统常见的问题是在文件写入到物理设备时,存储数据用的块
    很容易分散在整个设备中(称作碎片化,fragmentation)。数据块的碎片化会降低文件系统的性能,因为需要更长的时间在存储设备中查找特定文件的
    所有块。
    
    保存文件时,ext2 文件系统通过按组分配磁盘块来减轻碎片化。通过将数据块分组,文件系统在读取文件时不需要为了数据块查找整个物理设备。

    
8.1.2 日志文件系统
-----------------------------------------------------------------------------------------------------------------------------------------    
日志文件系统为 Linux 系统增加了一层安全性。它不再使用之前先将数据直接写入存储设备再更新索引节点表的做法,而是先将文件的更改写入到临时文件
(称作日志,journal)中。在数据成功写到存储设备和索引节点表之后,再删除对应的日志条目。如果系统在数据被写入存储设备之前崩溃或断电了,日志
文件系统下次会读取日志文件并处理上次留下的未写入的数据。


    ■ ext3 文件系统
    -------------------------------------------------------------------------------------------------------------------------------------
    2001年,ext3 文件系统被引入 Linux 内核中。它采用和 ext2 文件系统相同的索引节点表结构,但给每个存储设备增加了一个日志文件,以将准备写入
    存储设备的数据先记入日志。

    默认情况下,ext3 文件系统用有序模式的日志功能——只将索引节点信息写入日志文件,直到数据块都被成功写入存储设备才删除。用户可以在创建文件
    系统时用简单的一个命令行选项将 ext3 文件系统的日志方法改成数据模式或回写模式。


    ■ ext4 文件系统
    -------------------------------------------------------------------------------------------------------------------------------------
    扩展 ext3 文件系统功能的结果是 ext4 文件系统。ext4 文件系统在 2008 年受到 Linux 内核官方支持,现在已是大多数流行的 Linux 发行版采用的
    默认文件系统。
    
    除了支持数据压缩和加密,ext4 文件系统还支持一个称作区段(extent)的特性。区段在存储设备上按块分配空间,但在索引节点表中只保存起始块的
    位置。由于无需列出所有用来存储文件中数据的数据块,它可以在索引节点表中节省一些空间。
    
    ext4 还引入了块预分配技术(block preallocation)。如果想在存储设备上给一个知道要变大的文件预留空间,ext4 文件系统可以为文件分配所有需
    要用到的块,而不仅仅是那些现在已经用到的块。ext4 文件系统用 0 填满预留的数据块,不会将它们分配给其他文件。
    

    ■ Reiser 文件系统
    -------------------------------------------------------------------------------------------------------------------------------------
    2001年,Hans Reiser 为 Linux 创建了第一个称为 ReiserFS 的日志文件系统。ReiserFS 文件系统只支持回写日志模式——只把索引节点表数据写到日志
    文件。ReiserFS 文件系统也因此成为 Linux 上最快的日志文件系统之一。
    
    
    ■ JFS 文件系统
    -------------------------------------------------------------------------------------------------------------------------------------    
    作为可能依然在用的最老的日志文件系统之一,JFS(Journaled File System,日志化文件系统)是 IBM 在1990年为其 Unix 衍生版 AIX 开发的。然而
    直到第2版,它才被移植到 Linux 环境中。
    
    JFS 文件系统采用的是有序日志方法,即只在日志中保存索引节点表数据,直到真正的文件数据被写进存储设备时才删除它。这个方法在 ReiserFS 的速
    度和数据模式日志方法的完整性之间的采取的一种折中。
    
    
    ■ XFS 文件系统
    -------------------------------------------------------------------------------------------------------------------------------------
    XFS 日志文件系统是另一种最初用于商业 Unix 系统而如今走进 Linux 世界的文件系统。美国硅图公司(SGI)最初在1994年为其商业化的 IRIX Unix
    系统开发了 XFS。2002年,它被发布到了适用于 Linux 环境的版本。

    XFS 文件系统采用回写模式的日志,在提供了高性能的同时也引入了一定的风险,因为实际数据并未存进日志文件。XFS 文件系统还允许在线调整文件
    系统的大小,XFS 文件系统只能扩大不能缩小。
    
    
8.1.3 写时复制文件系统
-----------------------------------------------------------------------------------------------------------------------------------------
就文件系统而言,日志式的另一种选择是一种叫作写时复制(copy-on-write,COW)的技术。COW 利用快照兼顾了安全性和性能。如果要修改数据,会使用
克隆或可写快照。修改过的数据并不会直接覆盖当前数据,而是被放入文件系统中的另一个位置上。即便是数据修改已经完成,之前的旧数据也不会被重写。


    ■ ZFS 文件系统
    -------------------------------------------------------------------------------------------------------------------------------------
    COW 文件系统 ZFS 是由 Sun公司于 2005年研发的,用于 OpenSolaris 操作系统,从2008年起开始向 Linux移植,最终在2012年投入Linux产品的使用。

    ZFS 是一个稳定的文件系统,与 Resier4、Btrfs 和 ext4势均力敌。它最大的弱项就是没有使用 GPL 许可。自2013年发起的 OpenZFS 项目有可能改变
    这种局面。


    ■ Btrf 文件系统
    -------------------------------------------------------------------------------------------------------------------------------------
    Btrfs 文件系统是 COW 的新人,也被称为 B 树文件系统。它是由 Oracle公司于2007年开始研发的。Btrfs 在 Reiser4 的诸多特性的基础上改进了
    可靠性。另一些开发人员最终也加入了开发过程,帮助 Btrfs 快速成为了最流行的文件系统。究其原因,则要归于它的稳定性、易用性以及能够动态
    调整已挂载文件系统的大小。OpenSUSE Linux 发行版最近将 Btrfs 作为其默认文件系统。除此之外,该文件系统也出现在了其他 Linux 发行版中(
    如 RHEL),不过并不是作为默认文件系统。


8.2 操作文件系统
-----------------------------------------------------------------------------------------------------------------------------------------
Linux 提供了一些不同的工具,可以利用它们轻松地在命令行中进行文件系统操作。可使用键盘随心所欲地创建新的文件系统或者修改已有的文件系统。


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

fdisk 工具用来帮助管理安装在系统上的任何存储设备上的分区。它是个交互式程序,允许输入命令来逐步完成硬盘分区操作。

要启动 fdisk 命令,必须指定要分区的存储设备的设备名,另外还得有超级用户权限。

    $ sudo fdisk /dev/sdb
    [sudo] password for Christine:
    Device contains neither a valid DOS partition table,
    nor Sun, SGI or OSF disklabel
    Building a new DOS disklabel with disk identifier 0xd3f759b5.
    Changes will remain in memory only
    until you decide to write them.
    After that, of course, the previous content won't be recoverable.
    Warning: invalid flag 0x0000 of partition table 4 will
    be corrected by w(rite)
    [...]
    Command (m for help):

fdisk 交互式命令提示符使用单字母命令来告诉 fdisk 做什么:输入 m 获得命令帮助。

可以用 p 命令将一个存储设备的详细信息显示出来:
    
    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: 0x11747e88
    Device Boot Start End Blocks Id System
    Command (m for help):

可以使用n命令在该存储设备上创建新的分区。
    Command (m for help): n
    Command action
    e extended
    p primary partition (1-4)

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

创建了想要的分区之后,用 w 命令将更改保存到存储设备上。

    Command (m for help): w
    The partition table has been altered!
    Calling ioctl() to re-read partition table.
    Syncing disks.

存储设备的分区信息被写入分区表中,Linux 系统通过 ioctl() 调用来获知新分区的出现。设置好分区之后,可以使用 Linux文件系统对其进行格式化。


8.2.2 创建文件系统
-----------------------------------------------------------------------------------------------------------------------------------------
在将数据存储到分区之前,必须用某种文件系统对其进行格式化,这样 Linux 才能使用它。每种文件系统类型都用自己的命令行程序来格式化分区。

命令:mkfs

用法:
        mkfs [-t 文件系统格式] 设备
        mkfs [选项] [-t <类型>] [文件系统选项] <设备> [<大小>]

        
    选项与参数:
         -t :后接文件系统格式,如:xfs, ext4, ext3, ext2, vfat 等(只有系统支持才会生效)
        设备: 指分区的设备文件绝对路径,如:/dev/sdc1
    
    范例:使用 xfs 格式化分区 /dev/sdc1
    
        mkfs -t xfs /dev/sdc1
    
    
    执行下面指令:
    -------------------------------------------------------------------------------------------------------------------------------------
    [root@www ~]# mkfs[tab][tab] <==按两个[tab]
    
    结果:
        mkfs         mkfs.cramfs  mkfs.ext3    mkfs.fat     mkfs.msdos   mkfs.xfs
        mkfs.btrfs   mkfs.ext2    mkfs.ext4    mkfs.minix   mkfs.vfat

    说明:     mkfs 实际上是一个综合指令,执行时会根据不同的文件系统格式类型选择对应的格式化工具执行格式化任务。例如 mkfs -t xfs, 实际执行的是
            mkfs.xfs 工具命令。
            vfat 可用于 Windows/Linux 共享的 U 盘或移动硬盘文件格式。

 

8.2.3 文件系统的检查与修复
-----------------------------------------------------------------------------------------------------------------------------------------
fsck 命令能够检查和修复大部分类型的 Linux 文件系统。
用法:
        
        fsck [-t 文件系统] [-ACay]  [filesys ... ] [--] [ fs-specific-options ]
 
    选项与参数:
        -t :如同 mkfs 一样,fsck 也是个综合软件,因此同样需要指定文件系统。 不过由于现在的 Linux 很智能,它会通过 superblock 自动判断文件系统,
             因此通常可以省略该选项。
        -A :根据 /etc/fstab 的内容,将需要的设备扫瞄一次。通常开机过程会执行此命令。
        -a :自动修复检查到的有问题的扇区,所以不用一直按 y 键。
        -y :与 -a 类似,但是某些 filesystem 仅支持 -y 这个参数。
        -C :可以在检查过程当中,使用一个直方图来显示当前进度。
        
        filesys ... : 可以是一个设备名(例如: /dev/hdc1, /dev/sdb2), 一个挂载点(例如: /, /usr, /home), 或一个ext2文件系统的磁盘标签, 也可以是UUID
        指定符(例如: UUID=8868abf6-88c5-4a83-98b8-bfc24057f7bd 或 LABEL=root). 通常,fsck 会试着以并行的方式同时在不同的物理磁盘上运行文件系统
        检查,这样可以减少对所有文件系统进行检查的时间。
        
        如果没有在命令行指定文件系统,并且没有指定 -A 选项,fsck 将默认顺序地检查 /etc/fstab 中登记的文件系统。这和使用  -As 选项是相同的。

    
    执行:
    -----------------------------------------------------------------------------------------------------------------------------------------
    [root@www ~]# fsck[tab][tab] <==按两个[tab]
    
    结果:
        fsck         fsck.cramfs  fsck.ext3    fsck.fat     fsck.msdos   fsck.xfs
        fsck.btrfs   fsck.ext2    fsck.ext4    fsck.minix   fsck.vfat

    说明:
        实际上,fsck 只是 Linux 中不同的文件系统检查器(fsck.fstype)的一个前端。首先,它在 /sbin 中搜索特定文件系统的检查器,然后在 /etc/fs 和
        /etc 中搜索,最后在 PATH 环境变量中列出的路径中搜索。
    
    
    执行 fsck 时,被检查 partition 分区不可挂载到系统上,亦即需要在卸载状态下。

 

(本篇完)

 

系列目录: 

    走进 Linux shell (一)

    走进 Linux shell (二)

    走进 Linux shell (三)

 

 

参考:

    《Linux 命令行与 shell 脚本编程大全》 第 3 版 —— 2016.8(美)Richard Blum  Cristine Bresnahan

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章