内容概述

  • 文件系统目录结构
  • 创建和查看文件
  • 复制、转移和删除文件
  • 软链接和硬链接
  • IO重定向和管道

    1 文件系统目录结构

    image.png

  • /bin:该目录是 Binaries(二进制文件)的缩写,这个目录是存放最经常使用的命令

  • /boot:该目录是存放启动Linux时使用的一些核心文件,包括一些连接文件以及镜像文件;存放跟操作系统启动和操纵系统相关的文件。例如内核Kernel文件
  • /dev:该目录是 Device(设备)的缩写,该目录是存放的是Linux的外部设备,在Linux中访问设备的方式和访问文件的方式是相同的。
  • /etc:该目录是存放所有系统管理所需要的配置文件和子目录 ;作用相当于Windows的注册表
  • /home:用户的主目录,在Linux系统中,每个用户都有一个自己的目录,一般该目录名是以用户的账号命名。
  • /lib:该目录是 Library(库)的缩写,这个目录是存放系统最基本的动态连接共享库。 /lib 是对应32位操作系统的库和 /lib64 是对应64位操作系统的库
  • /lost+found:当系统非法关机后,就会存放相应的日志文件。
  • /mnt:系统提供该目录是为了让用户临时挂载别的文件系统。
  • /opt:系统给主机额外安装软件所摆放的目录
  • /proc:是 Processes(进程)的缩写,是一种伪文件系统(也即虚拟文件系统),存储的是当前内核运行状态的一系列特殊文件,这个目录是虚拟的目录,它是系统内存的映射,通过直接访问这个目录获取系统信息。
    这个目录的内容不在硬盘上而是在内存中,可以通过修改里面的某些文件,比如可以通过命令来屏蔽主机的ping命令,使得别人无法ping你的机器。

存放的是内存中正在运行的系统状态信息,数据不在硬盘而是在内存中

  1. echo 1 > /proc/sys/net/ipv4/icmp_echo_ignore_all
  • /root:该目录为系统管理员,也称作超级权限者的用户家目录
  • /run:是一个临时文件系统,存储系统启动以来的消息。当系统重启时,这个目录下的文件一个被删除和清除。 存放系统运行时产生的临时文件,程序运行完毕后就会删除,是程序运行期间生成的文件
  • /sbin:s 是 Super User 的意思,是 Superuser Binaries(超级管理员的二进制文件)的缩写,这里存放的是系统管理员使用的系统管理程序。
  • /selinux:这个目录是 Redhat/CentOS 所特有的目录,Selinux 是一个安全机制,类似于Windows的防火墙。
  • /srv:该目录是存放一些服务启动之后需要提取的数据
  • /tmp:是 Temporary(临时)的缩写这个目录是用来存放一些临时文件的。
  • /sys:该文件系统是内核设备树的一个直观反映。当一个内核对象被创建的时候,对应的文件和目录也在内核对象子系统中被创建。 /sys 中存放的数据也是在内存中,是一种伪文件系统(也即虚拟文件系统)
  • /usr:是Unix Shared Resources(共享资源)的缩写,该目录是用户的很多用户程序和文件都存放的目录,类似于Windows下的 Program Files 目录。
  • /usr/bin:系统用户使用的应用程序
  • /usr/sbin:超级用户使用比较高级的管理程序和系统守护程序
  • /var:是 Variable(变量)的缩写,这个目前存放着不断扩充着的东西,包括各种日志文件。

    1.1 文件系统的目录结构

    Linux 操作系统 ext / xfs 文件系统是区分大小写,大小写敏感

  • 文件和目录被组织成一个单根倒置树的结构

  • 文件系统从根目录下开始,用 “ / ” 表示
  • 根文件系统(rootfs):root filesystem
  • 标准Linux文件系统(如:ext4),文件名称大小写敏感,例如:MAIL,Mail,mail,mAiL
  • 以 . 开头的文件为隐藏文件
  • 路径分隔的 /
  • 文件名最长为 255 个字节(如果是普通的汉字,则文件名最长可以输入 85 个字节)
  • 包括路径在内文件名称最长 4095 个字节
  • 蓝色 → 目录;绿色 → 可执行文件;红色 → 压缩文件;浅蓝色 → 链接文件;灰色 → 其他文件(查看系统的后缀的颜色定义:$ cat /etc/DIR_COLORS
  • 除了斜杠和NULL,所有字符都有效,但是使用特殊字符的目录名和文件不推荐使用,有些字符需要用引号来引用
  • 每个文件都有两类相关数据:
    • 元数据:metadata(文件属性)
    • 数据:data(文件内容)

Linux的文件系统分层结构:FHS Filesystem Hierarchy Standard
参考文档:http://www.pathname.com/fhs

1.2 常见的文件系统目录结构

  • /boot :引导文件存放目录,内核文件(vmlinux)、引导加载器(bootloader,grub)都是存放于此目录中
  • /bin :所有用户使用的基本命令(二进制程序);不能关联独立分层,OS启动即会用到的程序
  • /sbin :管理类的基本命令;不能关联独立分层,OS启动即会用到的程序
  • /lib :启动时程序依赖的基本共享库文件以及内核模块文件(/lib/modules)
  • /sbin :专用于 x86_64 系统上的辅助共享库存放位置
  • /etc :配置文件目录
  • /home/USERNAME :普通用户家目录,存放用户数据
  • /root :管理员的家目录
  • /media :便携式移动设备挂载点
  • /run:存放正在运行的程序,产生的临时数据回存放该目录
  • /mnt :临时文件系统挂载点
  • /dev :设备文件以及特殊文件存储位置
    • b :block device,块设备,随机访问
    • c :character device,字符设备,线性访问
  • /opt :第三方应用程序的安装位置
  • /srv :系统上运行的服务用到的数据
  • /tmp :临时文件存储位置
  • /usr :universal shared,read-only data;Unix System Resource,Unix操作系统软件资源所放置的目录(类似于Windows系统中的window)
    • bin :保证系统拥有完整功能而提供的应用程序
    • sbin :管理类的基本命令
    • lib :32 位系统使用
    • lib64 :只存在 64 位系统
    • include :C 程序的头文件(header files)
    • share :结构化独立的数据,例如 doc,man等等
      • local :第三方应用程序的安装位置
      • bin,sbin,lib,lib64,etc。share
  • /var :variable data files 存放常态性变动的文件
    • cache :应用程序缓存数据目录
    • lib :应用程序状态信息数据
    • local :专用于为 /usr/local 下的应用程序存储可变数据
    • lock :锁文件
    • log :日志目录及文件
    • opt :专用于为 /opt 下的应用程序存储可变数据
    • run :运行中的基础相关数据,通常用于存储进程 pid 文件
    • spool :应用程序的数据池
    • tmp :保存系统两次重启之间产生的临时数据
  • /proc :用于输出内核与进程信息相关的虚拟文件系统(内存信息)
  • /sys :用于输出当前系统上硬件设备相关信息虚拟文件系统(硬件缓存信息)
  • /selinux :security enhanced Linux,selinux 相关的安全策略等信息的存储位置

    1.3 应用程序的组成部分

    二进制程序:/bin,/sbin,/usr/bin,/usr/sbin,/usr/local/bin,/usr/local/sbin
    库文件:/lib,/lib64,/usr/lib,/usr/lib64,/usr/local/lib,/usr/local/lib64
    配置文件:/etc,/etc/DIRECTORY,/usr/local/etc
    帮助文件:/usr/share/man,/usr/share/doc,/usr/local/share/man,/usr/local/share/doc

    1.4 CentOS 7 以后版本目录结构变化

  • /bin 和 /usr/bin

  • /sbin 和 /usr/sbin
  • /lib 和 /usr/lib
  • /lib64 和 /usr/lib64

    $ ls -ld /bin /usr/bin /sbin /usr/sbin
    lrwxrwxrwx. 1 root root     7 Oct 30  2020 /bin -> usr/bin
    lrwxrwxrwx. 1 root root     8 Oct 30  2020 /sbin -> usr/sbin
    dr-xr-xr-x. 2 root root 28672 May  4 01:51 /usr/bin
    dr-xr-xr-x. 2 root root 12288 May  4 01:51 /usr/sbin
    

    1.5 Linux 下的文件类型

  • -:普通文件

  • d:目录文件
  • b:块设备
  • c:字符设备
  • l:符号链接文件
  • p:管道文件pipe(单向通信,目的是为了实现程序之间通信)
  • s:套接字文件socket(双向 | 网络通信,目的是为了实现程序之间通信)
    • 块设备和字符设备,管道文件和套接字文件都不是人为创建的,而是由应用程序生成的 ```bash $ ls -l / lrwxrwxrwx. 1 root root 7 Nov 3 2020 bin -> usr/bin …省略…

$ ls -l /run/ total 44 -rw———-. 1 root root 11 May 4 01:50 alsactl.pid drwxr-xr-x. 2 root root 60 May 4 01:50 dbus prw———-. 1 root root 0 May 4 01:50 dmeventd-client srw-rw-rw-. 1 root root 0 May 4 01:50 gssproxy.sock …省略…

$ ls -l /dev/ total 0 crw-r—r—. 1 root root 10, 235 May 4 01:50 autofs brw-rw——+ 1 root cdrom 11, 0 May 4 01:50 sr0 crw-rw-rw-. 1 root root 1, 5 May 4 01:50 /dev/zero …省略…

**块设备和字符设备**

- **块设备和字符设备均存放在 /dev 目录下**
- 字符设备按照字符流的方式被有序访问,块设备是随机(无序的)访问的。
- 块设备通过系统缓存进行读取,不是直接和物理磁盘读取。字符设备可以直接物理磁盘读取,不经过系统缓存。
- 当访问硬盘的时候,块设备会以一块一块block的方式进行访问(类似批量访问),而字符设备则会以一个字符一个字符的方式进行访问。

<a name="OMoLv"></a>
# 2 文件操作命令
<a name="UemGz"></a>
## 2.1 显示当前工作目录
每个 Shell 和系统进程都有一个当前的工作目录 CWD:Current Word Directory<br />显示当前 Shell CWD 的绝对路径<br />pwd 命令:printing working directory

- -P:显示目录真实物理路径
- -L:显示目录链接路径(默认)

范例:
```bash
$ pwd
/root

$ ls -ld /bin /sbin /usr/bin /usr/sbin
lrwxrwxrwx. 1 root root     7 Oct 30  2020 /bin -> usr/bin
lrwxrwxrwx. 1 root root     8 Oct 30  2020 /sbin -> usr/sbin
dr-xr-xr-x. 2 root root 28672 May  4 01:51 /usr/bin
dr-xr-xr-x. 2 root root 12288 May  4 01:51 /usr/sbin

$ cd /bin
# 显示目录连接路径
$ pwd
/bin
# 显示目录真实物理路径
$ pwd -P
/usr/bin

2.2 绝对路径和相对路径

  • 绝对路径:以正斜杠 / 开始,即根目录开始
    • 完整的文件的位置路径;
    • 可用于任何想指定一个文件名的时候;
  • 相对路径:不以正斜杠开始
    • 一般情况下,是指定相对于当前工作目录或者某目录的位置;特殊场景下,是相对于某个目录的位置
    • 可以作为一个简短的形式指定一个文件名;
    • 生产环境中使用相对路径会比较多,适合于项目的搬迁。
  • 基名:basename,只取文件名而不要路径;
  • 目录名:dirname,只取路径,不要文件名;

范例:

$ ls -l /etc/sysconfig/network-scripts/ifcfg-eth0
-rw-r--r--. 1 root root 130 Feb  5  2021 /etc/sysconfig/network-scripts/ifcfg-eth0
# 取绝对路径或相对路径的基名
$ basename /etc/sysconfig/network-scripts/ifcfg-eth0
ifcfg-eth0
# 在root家目录运行
$ basename ../etc/sysconfig/network-scripts/ifcfg-eth0
ifcfg-eth0

# 取绝对路径或相对路径的目录名
$ dirname /etc/sysconfig/network-scripts/ifcfg-eth0
/etc/sysconfig/network-scripts
$ dirname ../etc/sysconfig/network-scripts/ifcfg-eth0
../etc/sysconfig/network-scripts

2.3 更改目录

命令 cd:change directory
选项:-P 切换至物理路径,而非软连接目录
可以使用绝对路径或者相对路径

  • 切换至父目录:cd ..
  • 切换至当前用户家目录:cd ,cd ~ ,cd ~wang(切换到指定用户家目录)
  • 切换至一起的工作目录:cd -
  • 切换到上一级目录:cd ..
  • 当前目录:cd .

范例:

~ $ cd /etc/sysconfig/
/etc/sysconfig$ pwd

/data $ cd ../../data/
/data $ pwd

/data $ cd /bin/
/bin $ pwd

/bin $ cd -P /bin/
/usr/bin $ pwd

相关的环境变量:

  • PWD:当前目录路径;
  • OLDPWD:上一级目录路径; ```bash $ pwd /root $ cd /bin $ pwd /bin

使用相关环境变量

$ echo $PWD /bin $ echo $OLDPWD /root

cd - 中是判断 PWD 和 OLDPWD 两个环境变量的值进行更改目录

$ pwd /root $ cd /bin

切换到/root

$ cd - /root

切换到/bin

$ cd - /bin

修改环境变量OLDPWD的值

$ OLDPWD=/etc/sysconfig/network-scripts/ $ cd - /etc/sysconfig/network-scripts/

<a name="Tcnzi"></a>
## 2.4 列出目录内容
ls 命令可以列出当前目录的内容或者指定目录<br />用法:
```bash
Usage: ls [OPTION]... [FILE]...

常见选项:

  • -a :包含隐藏文件
  • -l :显示额外的信息,列出详细信息
  • -R :目录递归(重要)
  • -r:倒序显示
  • -ld :目录和符号链接信息(只查看目录和文件的信息)
  • -l :文件分行显示
  • -S :按从大到小排序
  • -t :按 mtime 排序(默认以文件和目录的修改时间为准)
  • -u :配置 -t 选项,显示并按照 atime 从新到旧排序
  • -U :按目录存放顺序显示
  • -X :按文件后缀排序
  • -F :对不同类型文件显示附加不同的符号:*/=>@|
  • -C :文件多时,以多列的方式显示文件,默认是一列(标准输出)

说明:

ls 查看不同后缀文件时的颜色由 /etc/DIR_COLORS 和 $LS_COLORS 变量定义
ls -l 看到文件的大小,不一定是实际文件真正占用空间的大小

范例:

# 查看当前目录下的内容
$ ls 
# 文件分行并倒序显示
$ ls -lr
# 文件分行并目录递归
$ ls -lR
# 对不同类型文件显示附加不同的符号:*/=>@|
$ ls -lF
# 按从大到小排序
$ ls -lS

# 显示以访问时间为标准
$ ls -l --time=atime a.txt
# 显示以改变时间为标准
$ ls -l --time=ctime a.txt

# 列出文件后缀的颜色
$ vim /etc/DIR_COLORS
$ echo $LS_COLORS

范例:别名ll

# CentOS
$ alias ll
alias ll='ls -l --color=auto'

# Ubuntu
$ alias ll
alias ll='ls -alF'

2.5 查看文件状态:stat

文件相关信息:metadata,data
每个文件有三个时间戳:

  • Access time:访问时间,atime,读取文件内容
    • access time > 1 day 会触发更新
    • 当modify time 修改时间比access time 访问时间要新,会触发更新
    • 只有满足特定情况下才会更新 atime,从而减少磁盘的写操作
  • Modify time:修改时间,mtime,改变文件内容(数据)
  • Change time:改变时间,ctime,元数据发生改变(文件属性)

    $ stat /etc/passwd
    File: ‘/etc/passwd’
    Size: 1081            Blocks: 8          IO Block: 4096   regular file
    Device: fd01h/64769d    Inode: 252112      Links: 1
    Access: (0644/-rw-r--r--)  Uid: (    0/    root)   Gid: (    0/    root)
    Access: 2022-05-05 09:14:47.401365176 +0800
    Modify: 2022-05-05 09:14:47.390365103 +0800
    Change: 2022-05-05 09:14:47.391365109 +0800
    Birth: -
    

    2.6 确定文件内容

    文件可以包含多种类型的数据,使用 file 命令检查文件的类型,然后确定适当的打开命令或者应用程序使用
    Linux 对文件的后缀不敏感,Windows 对文件的后缀敏感
    格式:

    Usage: file [OPTION...] [FILE...]
    

    常用选项:

  • -b :列出文件辨识结果时,不显示文件名称

  • -f filelist :列出文件 filelist 中文件名的文件类型
  • -F :使用指定分隔符号替换文件名后默认的 “:” 分隔符
  • -L :查看对应软连接对应文件的文件类型
  • —help :显示命令在线帮助

范例:windows的文本格式和linux的文本格式的区别

$ cat linux.txt
a
b
c
$ cat windows.txt
a
b
c

$ file linux.txt
linux.txt: ASCII text
$ file windows.txt
windows.txt: ASCII text, with CRLF line terminators

# 安装转换工具
$ yum install -y dos2unix

# 将windows的文本格式转换为linux的文本格式
$ dos2unix 
dos2unix: converting file windows.txt to Unix format ...
$ file windows.txt
windows.txt: ASCII text

# 将linux的文本格式转换为windows的文本格式
$ unix2dos linux.txt
unix2dos: converting file linux.txt to DOS format ...
$ file linux.txt
linux.txt: ASCII text, with CRLF line terminators

范例:转换文件字符集编码

$ vim file.txt
/etc
/etc/issue

$ file -f file.txt
/etc:       directory
/etc/issue: ASCII text

2.7 文件通配符 wild-card pattern

文件通配符可以用来匹配符合条件的多个文件,方便批量管理文件
通配符采用特定的符号,表示特定的含义,此特符号称为元字符,. 就是 .
常见的通配符如下:

  • :匹配零个或者多个字符,但是不匹配 “.” 开头的文件,其隐藏文件 ? :匹配任何单个字符,一个汉字也算一个字符 ~ :当前用户家目录 ~mage :用户 mage 家目录 ~+ 和 . :当前工作目录 ~- 和 - :前一个工作目录 [0-9] :匹配数字范围 [a-z] :匹配字母范围,匹配字母的顺序为小写字母,大写字母匹配 [A-Z] :匹配字母范围,匹配字母的顺序为大写字母,小写字母匹配 [wang] :匹配列表中的任何的一个字符 [^wang] :匹配列表中的所有字符以外的字符

另外还有在Linux系统中预定义的字符类:man 7 glob

[:alnum:]:字母和数字,示例:[[:alnum:]]

[:digit:]:十进制数字,示例:[[:digit:]]

[:punct:]:标点符号,示例:[[:punct:]]

[:alpha:]:代表任何英文大小写字符,亦即 A-Z,a-z,示例:[[:alpha:]]

[:graph:]:可打印的非空白字符,示例:[[:graph:]]

[:space:]:水平和垂直的空白字符(比[:blank:]包含的范围广),示例:[[:space:]]

[:blank:]:空白字符(空格和制表符),示例:[[:blank:]]

[:lower:]:小写字母,示例:[[:lower:]]

[:upper:]:大写字符,示例:[[:upper:]]

[:cntrl:]:不可打印的控制字符(退格,删除,警铃……)示例:[[:cntrl:]]

[:print:]:可打印字符,示例:[[:print:]]

[:xdigit:]:十六进制数字,示例:[[:xdigit:]]

范例:

$ echo "linux" > /data/linux.txt
$ echo $OLDPWD
/data

$ ls -l -/linux.txt
ls: invalid option -- '/'
Try 'ls --help' for more information.
$ ls -l ~-/linux.txt
-rw-r--r--. 1 root root 6 May  5 10:56 /data/linux.txt

范例:

$ touch f{3..4}.txt
$ ls -l f{3..5}.txt
ls: cannot access 'f5.txt': No such file or directory
-rw-r--r--. 1 root root 0 May  5 10:58 f3.txt
-rw-r--r--. 1 root root 0 May  5 10:58 f4.txt
$ ls -l f[3-5].txt
-rw-r--r--. 1 root root 0 May  5 10:58 f3.txt
-rw-r--r--. 1 root root 0 May  5 10:58 f4.txt

$ ls -l f[a-c]
-rw-r--r--. 1 root root 0 May  5 11:00 fa
-rw-r--r--. 1 root root 0 May  5 11:00 fA
-rw-r--r--. 1 root root 0 May  5 11:00 fb
-rw-r--r--. 1 root root 0 May  5 11:00 fB
-rw-r--r--. 1 root root 0 May  5 11:00 fc
$ ls -l f{a..c}
-rw-r--r--. 1 root root 0 May  5 11:00 fa
-rw-r--r--. 1 root root 0 May  5 11:00 fb
-rw-r--r--. 1 root root 0 May  5 11:00 fc
$ touch file{a..z}.txt file{A..Z}.txt file{0..9}.txt
$ ls -l file{0..9}.txt 
$ ls -l file[0-9].txt
$ ls -l file[[:digit:]].txt
# 效果一致

$ ls file[a-c].txt
filea.txt  fileA.txt  fileb.txt  fileB.txt  filec.txt
$ ls file[C-E].txt
fileC.txt  filed.txt  fileD.txt  filee.txt  fileE.txt

$ ls file[wang].txt
filea.txt  fileg.txt  filen.txt  filew.txt
$ ls file{w,a,n,g}.txt
filea.txt  fileg.txt  filen.txt  filew.txt
$ ls file[^wang].txt
$ ls file[:lower:].txt
filee.txt  filel.txt  fileo.txt  filer.txt  filew.txt file:.txt
$ ls file[[:lower:]].txt
filea.txt  filee.txt  filei.txt  filem.txt  fileq.txt  fileu.txt  filey.txt
fileb.txt  filef.txt  filej.txt  filen.txt  filer.txt  filev.txt  filez.txt
filec.txt  fileg.txt  filek.txt  fileo.txt  files.txt  filew.txt
filed.txt  fileh.txt  filel.txt  filep.txt  filet.txt  filex.txt

范例:比较有无 * 的功能区别

ls -a 
# * 会自动过滤掉隐藏文件和目录
ls -a *
$ alias l.
alias l.='ls -d .* --color=auto'
$ l.
$ ls -d /etc/*/
$ touch file*.log
$ touch file1.log
$ ls file*.log
 file1.log  'file*.log'
$ ls 'file*.log'
'file*.log'

2.7.1 练习:

# 1、显示/etc目录下所有以l开头,以一个小写字母结尾,且中间出现至少一位数字的文件或目录
# 2、显示/etc目录下以任意一位数字开头,且以非数字结尾的文件或目录
# 3、显示/etc/目录下以非字母开头,后面跟了一个字母及其它任意长度任意字符的文件或目录
# 4、显示/etc/目录下所有以rc开头,并后面是0-6之间的数字,其它为任意字符的文件或目录
# 5、显示/etc目录下,所有.conf结尾,且以m,n,r,p开头的文件或目录
# 6、只显示/root下的隐藏文件和目录
# 7、只显示/etc下的非隐藏目录
# 8、只显示/etc下的隐藏文件
# 1、显示/etc目录下所有以l开头,以一个小写字母结尾,且中间出现至少一位数字的文件或目录
ls -l /etc/l*[0-9]*[[:lower:]]
ls -l /etc/l*[[:digit:]]*[[:lower:]]

# 2、显示/etc目录下以任意一位数字开头,且以非数字结尾的文件或目录
ls -l /etc/[0-9]*[^0-9]
ls -l /etc/[[:digit:]]*[^[:digit:]]

# 3、显示/etc/目录下以非字母开头,后面跟了一个字母及其它任意长度任意字符的文件或目录
ls -l /etc/[^a-zA-Z][a-zA-Z]*
ls -l /etc/[^[:alpha:]][[:alpha:]]*

# 4、显示/etc/目录下所有以rc开头,并后面是0-6之间的数字,其它为任意字符的文件或目录
ls -l /etc/rc[0-6]*

# 5、显示/etc目录下,所有.conf结尾,且以m,n,r,p开头的文件或目录
ls -l /etc/[mnrp]*.conf
ls -l /etc/{m,n,r,p}*.conf

# 6、只显示/root下的隐藏文件和目录
ls -ld /root/.*

# 7、只显示/etc下的非隐藏目录
ls -ld /etc/[^.]* | grep "^d"

# 8、只显示/etc下的隐藏文件
ls -ld /etc/.*
ls -ld /etc/.* | grep "^-"

2.8 创建空文件和刷新时间

touch 命令可以用来创建空文件和刷新文件的时间
格式:

touch [OPTION]... FILE ...

选项说明:

  • -a:仅改变 atime 和 ctime
  • -m:仅改变 mtime 和 ctime
  • -t [[CC]YY]MMDDhhmm[.ss]:指定 atime 和 mtime 的时间戳
  • -c:如果文件不存在,则不予以创建

范例:

$ touch 1.txt
# 可以创建空文件,如果有文件和创建的空文件同名,也不会进行覆盖,比较安全
$ > 2.txt
# > 可以创建空文件,如果有文件和创建的空文件同名,会破坏现有的文件内容

$ touch 1.txt
$ ls -l 1.txt
-rw-r--r--. 1 root root 0 May  5 14:16 1.txt
$ touch /etc/issue
# 刷新时间
$ stat /etc/issue
  File: /etc/issue
  Size: 23              Blocks: 8          IO Block: 4096   regular file
Device: fd00h/64768d    Inode: 201751071   Links: 1
Access: (0644/-rw-r--r--)  Uid: (    0/    root)   Gid: (    0/    root)
Context: system_u:object_r:etc_t:s0
Access: 2022-05-05 14:20:21.208242551 +0800
Modify: 2022-05-05 14:20:21.208242551 +0800
Change: 2022-05-05 14:20:21.208242551 +0800
 Birth: -

$ date
Thu May  5 14:21:09 CST 2022
$ touch `date -d "-1 day" +%F_%T`.log
$ touch $(date -d "-1 year" +%F_%T).log
# 常用做法
$ touch nginx_access_$(date +%F_%T).log

2.9 复制文件和目录

利用 cp(copy) 命令可以实现文件或者目录的复制
格式:

Usage: cp [OPTION]... [-T] SOURCE DEST
  or:  cp [OPTION]... SOURCE... DIRECTORY
  or:  cp [OPTION]... -t DIRECTORY SOURCE...
Copy SOURCE to DEST, or multiple SOURCE(s) to DIRECTORY.

常用选项:

  • -i :覆盖前提示
  • -n :不覆盖,注意两者顺序
  • -r,-R :递归复制及内部的所有内容
  • -a :归档,相当于 -dR —preserve=all
  • -d —no-dereference —preserve=links :不复制原文件,只复制链接名
  • —preserve[=ATTR_LIST]
    • mode :权限
    • ownership :属主属组
    • timestamp :时间戳
    • links :符号链接
    • xattr :扩展属性
    • context :上下文
    • all :保留所有属性
  • -p 等同 —preserve=mode ,ownership ,timestamp
    • -v —verbose :显示复制的过程
  • -f —force:强制复制文件或者目录
  • -u —update:只复制源比目标更新文件或者目标不存在的文件
  • -b :目标存在,覆盖前先备份,形式为 filename ~
  • —backup=numbered :目标存在,覆盖前先备份加数字后缀 | 源 \目 标 | 不存在 | 存在且为文件 | 存在且为目录 | | —- | —- | —- | —- | | 一个 文件 | 新建DEST,并将SRC中 内容填充至DEST中 | 将SRC中的内容覆盖至 DEST中 注意数据丢失风 险! 建议用 –i 选项 | 在DEST下新建与原文件同 名的文件,并将SRC中内容 填充至新文件中 | | 多个 文件 | 提示错误 | 提示错误 | 在DEST下新建与原文件同 名的文件,并将原文件内容 复制进新文件中 | | 目录 须使 用-r 选项 | 创建指定DEST同名目 录,复制SRC目录中所 有文件至DEST下 | 提示错误 | 在DEST下新建与原目录同 名的目录,并将SRC中内容 复制至新目录中 |

范例:

$ su zzw
$ echo "User zzw touch file" > /data/zzw.txt
$ ls -l zzw.txt
-rw-rw-r--. 1 zzw zzw 20 May  5 14:31 zzw.txt

$ su root
$ cp zzw.txt /opt/zzw.txt.bak
# 文件的属性发生了变化
$ ls -l /data/zzw.txt /opt/zzw.txt.bak
-rw-rw-r--. 1 zzw  zzw  20 May  5 14:31 /data/zzw.txt
-rw-r--r--. 1 root root 20 May  5 14:31 /opt/zzw.txt.bak

$ cp -av /data/zzw.txt /opt/zzw.txt.backup
'/data/zzw.txt' -> '/opt/zzw.txt.backup'
$ ls -l !*
ls -l -av zzw.txt /opt/zzw.txt.backup
-rw-rw-r--. 1 zzw zzw 20 May  5 14:31 zzw.txt
-rw-rw-r--. 1 zzw zzw 20 May  5 14:31 /opt/zzw.txt.backup

$ ls -l /etc/grub2.cfg
lrwxrwxrwx. 1 root root 22 Mar  3  2021 /etc/grub2.cfg -> ../boot/grub2/grub.cfg
# 拷贝的是符号链接指定的源文件
$ cp /etc/grub2.cfg /data/
$ ls -l /data/grub2.cfg
-rw-r--r--. 1 root root 6433 May  5 14:37 /data/grub2.cfg

# 保留符号链接
$ cp -av /etc/grub2.cfg /data/grub2.cfg.bak
'/etc/grub2.cfg' -> '/data/grub2.cfg.bak'
$ ls -l /data/grub2.cfg.bak
lrwxrwxrwx. 1 root root 22 Mar  3  2021 /data/grub2.cfg.bak -> ../boot/grub2/grub.cfg

# 拷贝目录
cp -av /etc /data/etcbackup
# cp 非幂等性,即同一个命令执行多次效果一样。
# cp -av /etc /data/etcbackup 使用第二次会出现/etc 拷贝到/data/etcbackup目录下

# 拷贝文件
$ echo zzw.txt{,.bak}
zzw.txt zzw.txt.bak
$ cp -av zzw.txt{,.bak}

$ cp /data/issue{,.bak}
# -b 只能保留最新的版本
$ cp -b /etc/passwd /data/issue.bak
cp: overwrite '/data/issue.bak'? y
$ ls -l issue*
-rw-r--r--. 1 root root   23 May  5 15:33 issue
-rw-r--r--. 1 root root 2545 May  5 15:38 issue.bak
-rw-r--r--. 1 root root   23 May  5 15:36 issue.bak~

# 目标存在,覆盖前先备份加数字后缀
$ cp --backup=numbered /etc/group /data/issue.bak
cp: overwrite '/data/issue.bak'? y
$ ls -l issue*
-rw-r--r--. 1 root root   23 May  5 15:33 issue
-rw-r--r--. 1 root root  979 May  5 15:40 issue.bak
-rw-r--r--. 1 root root   23 May  5 15:36 issue.bak~
-rw-r--r--. 1 root root 2545 May  5 15:38 issue.bak.~1~
# 执行多次cp --backup=numbered,会备份多次文件并在文件后加上数字后缀
# 错误的做法
$ cp /dev/zero /data/zero


# 因为/dev/zero 是一个块设备,直接cp命令拷贝会拷贝无数个0的普通文件
# 正确的写法
$ cp -av /dev/zero /data/zero

练习:

# 1.每天将/etc/目录下所有文件,备份到/data独立的子目录下,并要求子目录格式为 backupYYYY-mm-dd,备份过程可见
# 2.创建/data/rootdir目录,并复制/root下所有文件到该目录内,要求保留原有权限
# 1.每天将/etc/目录下所有文件,备份到/data独立的子目录下,并要求子目录格式为 backupYYYY-mm-dd,备份过程可见
mkdir -pv /data
cp -av /etc /data/backup$(date +%F)

# 2.创建/data/rootdir目录,并复制/root下所有文件到该目录内,要求保留原有权限
mkdir -pv /data/rootdir
cp -av /root/* /data/rootdir

2.10 移动和重命名文件

mv (move)命令可以实现文件或者目录的移动和改名。
同一分区移动数据,速度很快(数据位置没有变化)
不同分区移动数据,速度相对慢(数据位置发生了变化)
格式:

Usage: mv [OPTION]... [-T] SOURCE DEST
  or:  mv [OPTION]... SOURCE... DIRECTORY
  or:  mv [OPTION]... -t DIRECTORY SOURCE...
Rename SOURCE to DEST, or move SOURCE(s) to DIRECTORY.

常用选项:

  • -i :如果指定移动的源目录或文件与目标的目录或文件同名,则会先询问是否覆盖旧文件,输入 y 表示直接覆盖,输入 n 表示取消该操作。
  • -f :如果指定移动的源目录或文件与目标的目录或文件同名,不会询问,直接覆盖旧文件
  • -b :当目标文件或者目录存在时,在执行覆盖前,会为其创建一个备份 | 命令格式 | 运行结果 | | —- | —- | | mv source_file(文件) dest_file(文件) | 将源文件名 source_file 改为目标文件名 dest_file | | mv source_file(文件) dest_directory(目录) | 将文件 source_file 移动到目标目录 dest_directory 中 | | mv source_directory(目录) dest_directory(目录) | 目录名 dest_directory 已存在,将 source_directory 移动到目录名 dest_directory 中;目录名 dest_directory 不存在则 source_directory 改名为目录名 dest_directory | | mv source_directory(目录) dest_file(文件) | 出错 |

可以利用 rename 可以批量修改文件名
格式:

Usage:
 rename [options] <expression> <replacement> <file>...

范例:

# 为所有的conf文件添加上 .bak 后缀
$ touch f{1..5}.conf
$ rename "conf" "conf.bak" f*
$ ls
f1.conf.bak  f2.conf.bak  f3.conf.bak  f4.conf.bak  f5.conf.bak

# 去掉所有的 .bak 后缀
$ rename ".bak" "" f*
$ rename "conf.bak" "conf" f*
# 将文件 aaa 改名为 bbb
mv aaa bbb

# 将info 目录放入 logs 目录中。注意,如果 logs 目录不存在,则该命令将 info 改名为 logs
mv info/ logs

# 再如将 /usr/runoob 下的所有文件和目录移到当前目录下,命令行为
mv /usr/runoob/* .

2.11 删除文件

image.png
使用 rm(remove) 命令可以删除文件
注意:此命令非常危险,慎重使用,建议使用 mv 代替 rm
格式:

Usage: rm [OPTION]... [FILE]...

常用选项:

  • -i :交互式
  • -f :强制删除
  • -r :递归
  • —no-preserve-root 删除 /

范例:

$ rm -rf /data/etc
$ alias rm
alias rm='rm -i'

### 注意千万不能使用 rm -rf /*
$ rm -rf /
rm: it is dangerous to operate recursively on ‘/’
rm: use --no-preserve-root to override this failsafe

# 思考删除/下的文件,如何进行验证
$ rm -rf /* # 真的可以删除 / 下所有的文件和目录
$ echo *
$ echo /*

范例:删除特殊文件

$ rm --help
...省略...
To remove a file whose name starts with a '-', for example '-foo',
use one of these commands:
  rm -- -foo
  rm ./-foo

# 将名为 “/data/-f” 的文件删除
### 遇到不正常的文件名,建议统一使用绝对路径或者相对路径进行删除操作
$ rm -rf -f # 此方法错误
# 正确的做法
$ rm -rf -- -f
$ rm -rf # 使用绝对路径或者相对路径(rm ./-f | rm /data/-f)

$ touch '~'
$ rm -f ~
rm: cannot remove '/root': Is a directory
$ rm -- ~
rm: cannot remove '/root': Is a directory
$ rm -rf ./~
$ cp /dev/zero /boot/bigfile.img
$ df -Th | grep boot
/dev/sda1      xfs       2.0G  2.0G   32K 100% /boot
$ ls -lhS /boot/
total 2.0G
-rw-r--r--. 1 root root 1.8G May  5 20:42 bigfile.img # 没有用的垃圾文件
$ vim /boot/bigfile.img # 新开终端执行

$ rm -rf /boot/bigfile.img
$ ls -lhS /boot | grep bigfile.img # 已经删除了大文件
# boot的分区利用率依旧是100%
$ df -Th | grep boot
/dev/sda1      xfs       2.0G  2.0G   32K 100% /boot

$ w
 20:51:33 up 19 min,  2 users,  load average: 1.00, 0.67, 0.31
USER     TTY      FROM             LOGIN@   IDLE   JCPU   PCPU WHAT
root     pts/0    10.0.0.1         20:32    1.00s  0.22s  0.01s w
root     pts/1    10.0.0.1         20:46    5:09   4:52   4:52  vim /boot/bigfile.img
# lsof 是一个列出当前系统打开文件的工具。
$ lsof | grep delete
vim       2530                          root    5r      REG                8,1 1880358912      34154 /boot/bigfile.img (deleted)
# boot的分区利用率将下降了
$ kill -9 2530
$ df -Th | grep boot
/dev/sda1      xfs       2.0G  245M  1.8G  13% /boot
$ dd if=/dev/zero of=/boot/bigfile.img
$ > /boot/bigfile.img # 但是该 > 依赖于Shell
### 更加通用的做法:什么Shell都支持
cat /dev/null > /boot/bigfile.img

$ df -Th
/dev/sda1      xfs       2.0G  245M  1.8G  13% /boot
$ rm -rf /boot/bigfile.img

shred 命令完全删除文件
rm 虽然删除了文件,但是被删除 的文件仍然可能被恢复,在安全要求较高的场景下,可以使用 shred 安全删除文件。
格式:

Usage: shred [OPTION]... FILE...
Overwrite the specified FILE(s) repeatedly, in order to make it harder
for even very expensive hardware probing to recover the data.

常见选项:

  • -z:最后一次覆盖添加 0 ,以隐藏覆盖操作
  • -v:能够显示操作进度
  • -u:覆盖后截断并删除文件
  • -n:指定覆盖文件内容的次数(默认值为 3 次) ```bash $ shred -zvun 5 passwd.txt shred: passwd.txt: pass 1/6 (random)… shred: passwd.txt: pass 2/6 (000000)… shred: passwd.txt: pass 3/6 (random)… shred: passwd.txt: pass 4/6 (ffffff)… shred: passwd.txt: pass 5/6 (random)… shred: passwd.txt: pass 6/6 (000000)… shred: passwd.txt: removing shred: passwd.txt: renamed to 0000000000 shred: 0000000000: renamed to 000000000 shred: 000000000: renamed to 00000000 shred: 00000000: renamed to 0000000 shred: 0000000: renamed to 000000 shred: 000000: renamed to 00000 shred: 00000: renamed to 0000 shred: 0000: renamed to 000 shred: 000: renamed to 00 shred: 00: renamed to 0 shred: passwd.txt: removed

$ ls passwd.txt ls: cannot access ‘passwd.txt’: No such file or directory

<a name="LP4VE"></a>
## 2.12 目录操作
<a name="hH2l0"></a>
### 2.12.1 显示目录树 tree
tree:以树状图列出当前目录结构<br />常见选项:

- -a 显示所有文件和目录。
- -d :只显示目录
- -L level :指定显示的层级数目
- -p 列出权限标示。
- -s 列出文件或目录大小。
- -P pattern :只显示由指定 wild-card pattern 匹配到的路径
- -u 列出文件或目录的拥有者名称,没有对应的名称时,则显示用户识别码
```bash
$ tree
.
├── dir1
│   ├── dir2
│   │   └── dir4
│   └── dir3
│       └── dir4
├── group
└── passwd.txt

5 directories, 2 files

$ tree -dp
.
└── [drwxr-xr-x]  dir1
    ├── [drwxr-xr-x]  dir2
    │   └── [drwxr-xr-x]  dir4
    └── [drwxr-xr-x]  dir3
        └── [drwxr-xr-x]  dir4

5 directories

2.12.2 创建目录 mkdir

常见选项:

  • -p:存在于不报错,并且可以自动创建所需的各目录
  • -v:显示详细信息
  • -m MODE:创建目录时直接指定权限

    2.12.3 删除空目录 rmdir

    常见选项:

  • -p:递归删除父空目录

  • -v:显示详细信息

注意:rmdir 只能删除空目录,如果想删除非空目录,可以使用 rm -r 命令,递归删除目录树
范例:

alias rm='DIR=/data/backup`date +%F_%T`;mkdir $DIR;mv -t $DIR'

2.12.4 练习

# (1) 如何创建/testdir/dir1/x, /testdir/dir1/y, /testdir/dir1/x/a, /testdir/dir1/x/b, /testdir/dir1/y/a,/testdir/dir1/y/b
# (2) 如何创建/testdir/dir2/x, /testdir/dir2/y, /testdir/dir2/x/a, /testdir/dir2/x/b
# (3) 如何创建/testdir/dir3, /testdir/dir4, /testdir/dir5, /testdir/dir5/dir6, /testdir/dir5/dir7
# (1) 如何创建/testdir/dir1/x, /testdir/dir1/y, /testdir/dir1/x/a, /testdir/dir1/x/b, /testdir/dir1/y/a,/testdir/dir1/y/b
mkdir -pv /testdir/dir1/{x,y}/{a,b}

# (2) 如何创建/testdir/dir2/x, /testdir/dir2/y, /testdir/dir2/x/a, /testdir/dir2/x/b
mkdir -pv /testdir/dir2/{x/{a,b},y}
mkdir -pv /testdir/dir2/x/{a,b} /testdir/dir2/y

# (3) 如何创建/testdir/dir3, /testdir/dir4, /testdir/dir5, /testdir/dir5/dir6, /testdir/dir5/dir7
mkdir -pv /testdir/dir{3,4,5/dir{6,7}}
mkdir -pv /testdir/dir{3,4,5} /testdir/dir5/dir{6,7}

## 可以用tree命令查看创建的目录

3 文件元数据和节点表结构

3.1 inode 表结构

每个文件的属性信息 meta data,比如:文件的大小,时间,类型,权限等等,称为文件的元数据(meta data)。这些元数据是存放在 node(index node)表中。node 表中有很多条记录组成,第一条记录对应的存放了一个文件的元数据信息。
第一个 node 表记录对应的保存了以下信息:

  • inode number 节点号
  • 文件类型
  • UID
  • GID
  • 链接数(指向这个文件名路径名称个数)
  • 该文件的大小和不同的时间戳
  • 指向磁盘上文件的数据块指针
  • 有关文件的其他数据

image.png
image.png
3 文件管理和IO重定向 - 图5

在硬盘的分区上,有一块空间用来存放文件和目录的元数据metadata,有一块空间用来存放真正的数据data 元数据的存放,每一个文件的元数据信息存放,被称为 inode 表。inode 表包含以下信息:

  • inode number 节点号
  • 文件类型
  • UID
  • GID
  • 链接数(指向这个文件名路径名称个数)
  • 该文件的大小和不同的时间戳
  • 指向磁盘上文件的数据块指针
  • 有关文件的其他数据

文件的元数据信息和真正的数据存放位置不同,所以就需要有数据指针(地址)来引导寻找真正数据的位置 指针可以分为:直接块指针、间接块指针、双重间接块指针、三重间接块指针 而每一个磁盘上存放数据的空间,会有一个分配单位:block 块(block 的大小通常是4K = 4096字节)

  1. 直接块指针:就是直接使用指针就找到了文件数据真实存放的位置;直接块指针一共有 12 个,12个指针就可以分别指向 12 个块 block;那么就是 12 * 4 = 48K 的数据。也就是说 直接块指针可以存放 48K 以内的数据内容。
  2. 间接块指针:当文件超过48K的数据大小,那么就会用到间接块指针;间接块指针是会指定到一个指针块 block 中,指针块也是 4K(4096 字节),指针块中一个小块就是占用空间为 4 个字节,那么指针块可以存放 1024 个指针。那么 1024 个指针指向的数据块存放为 4K,那么间接块指针可以存放 1024 * 4K = 4M。也就是说 间接块指针可以存放 4M 以内的数据内容。
  3. 双重间接块指针同理。跟套娃一样。那么双重间接块指针可以存放 1024 1024 4K = 4G。也就是说 双重间接块指针可以存放 4G 以内的数据内容。
  4. 三重间接块指针同理。也就是说 三重间接块指针可以存放 4T 以内的数据内容。

数据越大,指针就不是直接指向数据了,需要通过间接的手段实现。那么文件越大,找起来会慢。 Linux 操作系统中的文件系统在对底层元数据 metadata 和真实数据 data 的实现方式上各有不同之处。

在磁盘上,每个文件都会有一个与众不同的唯一标识,叫 inode number节点号;就像每个人都会唯一的身份证号一样。节点号是一个整数;就是文件的节点号来标识文件;节点号是每个分区独立分配的; 节点号也是宝贵的资源,每创建一个目录或者文件,都会消耗一个节点号

# 查看系统节点表空间利用率
$ df -Thi

# 查看物理分区空间利用率
$ df -Th
$ ls -il /data
total 0
131 -rw-r--r--. 1 root root 0 May  5 22:15 f1.txt
132 -rw-r--r--. 1 root root 0 May  5 22:15 f2.txt
133 -rw-r--r--. 1 root root 0 May  5 22:15 f3.txt
$ df -ih
Filesystem     Inodes IUsed IFree IUse% Mounted on
devtmpfs         457K   402  457K    1% /dev
tmpfs            464K     1  464K    1% /dev/shm
tmpfs            464K   858  463K    1% /run
tmpfs            464K    17  464K    1% /sys/fs/cgroup
/dev/sda2         50M  121K   50M    1% /
/dev/sda3         50M     9   50M    1% /data
/dev/sda1        1.0M   309  1.0M    1% /boot
tmpfs            464K    23  464K    1% /run/user/42
tmpfs            464K    11  464K    1% /run/user/0

# 不同的分区中分配的节点号可以相同。就像中国和印度可能会出现身份证号一样的情况,但是用来标识不同的人
# 同一个分区中分配的节点号可能会有重复,即同一个文件有多个名,比如硬链接。在磁盘上占用的空间是一份
$ ls -il /data | grep 131
131 -rw-r--r--. 1 root root 0 May  5 22:15 f1.txt
$ ls -il /boot | grep 131
    131 drwxr-xr-x. 3 root root        17 Jul 11  2021 efi

目录
目录是个特殊文件,文件内容保存了目录中文件的列表及 inode number

  • 文件引用一个是 inode 号
  • 人是通过文件名来引用一个文件
  • 一个目录是目录下的文件名和文件 inode 号之间的映射

inode 表和目录
3 文件管理和IO重定向 - 图6

目录是特殊的文件。 目录的元数据跟文件的元数据大致相同,只是在指针指向中,目录的指针指向的数据。目录的数据部分是目录下所有文件的列表(列表存放的是文件名+节点号)

cp 和 inode
cp 命令:

  • 分配一个空闲的 inode 号,在 inode 表中生成新的条目
  • 在目录中创建一个目录项,将名称与 inode 编号关联
  • 拷贝数据生成新的文件

rm 和 inode
rm 命令:

  • 链接数递减,从而释放的 inode 号可以被重用
  • 把数据块放在空闲列表中
  • 删除目录项
  • 数据实际上不会马上被删除,但是另一个文件使用数据块时将被覆盖

mv 和 inode

  • 如果 mv 命令的目标和源在系统的文件系统,作为 mv 命令:
    • 用新的文件名来创建对应新的目录项
    • 删除旧目录条目对应的旧的文件名
    • 不影响 inode 表(除了时间戳)或磁盘上的数据位置:没有数据被移动;
  • 如果目标和源在不同的文件系统,mv 相当于 cp 和 rm ```bash $ touch file{1..n}.txt -bash: /usr/bin/touch: Argument list too long

正确的写法

echo file{1..n}.txt | xargs touch

删除大量的空文件

echo file{1..n}.txt | xargs rm

> 节点编号用光的情况:只有分区中有大量的无用的小文件占用
> 解决方法:
> - 删除分区中无用的小文件
> - 修改inode的数量(注意该方法会丢失磁盘数据,建议操作前备份数据)

<a name="JL897"></a>
## 3.2 硬(Hard)链接
```bash
ln(link)
Usage: ln [OPTION]... [-T] TARGET LINK_NAME
  or:  ln [OPTION]... TARGET
  or:  ln [OPTION]... TARGET... DIRECTORY
  or:  ln [OPTION]... -t DIRECTORY TARGET...

硬链接本质上就给一个文件起一个新的名称,实质就是同一个文件
硬链接特性:

  • 创建硬链接会增加额外的记录项以引用文件
  • 对应于同一文件系统上一个物理文件
  • 每个目录引用相同的 inode 号
  • 创建时链接数递增
  • 删除文件时:rm 命令递减计数的链接,文件要存在,至少有一个链接数,当链接数为零时,该文件被删除
  • 不能跨越驱动器或分区
  • 不支持对目录创建硬链接

格式:

ln filename [linkname]
$ cp /etc/fstab /data/dir/f1.txt
$ ls -i dir/f1.txt
132 -rw-r--r--. 1 root root 709 May  7 20:17 /data/dir/f1.txt

$ ln /data/dir/f1.txt /data/f11.txt
$ ls -li !*
ls -li /data/dir/f1.txt /data/f11.txt
132 -rw-r--r--. 2 root root 709 May  7 20:17 /data/dir/f1.txt
132 -rw-r--r--. 2 root root 709 May  7 20:17 /data/f11.txt
节点号  权限   连接数

# 在文件中追加数据或者删除数据都会进行同步操作,本质上是一个文件。
# 不能跨越驱动器或分区
$ ln /data/f11.txt /opt/f11.txt
ln: failed to create hard link '/opt/f11.txt' => '/data/f11.txt': Invalid cross-device link
# 不支持对目录创建硬链接
$ ln /data/dir/ /data/dir2
ln: /data/dir/: hard link not allowed for directory
# 删除硬链接或者源文件时,并没有依赖关系,但是会减少链接数
### 如何一个目录的连接数至少是 2.

3.3 符号symbolic(或者软soft)链接

一个符号链接指向另一个文件,就像 windows 中快捷方式,软连接文件和源文件本质上不是同一个文件。
软连接特点:

  • 一个符号链接的内容是它引用文件的名称
  • 可以对目录创建软连接
  • 可以跨分区的文件实现
  • 指向的是另一个文件的路径;其大小为指向的路径字符串的长度(例如:ln -s /data/dir /data/dirlink,则 /data/dirlink 的大小就为 /data/dir 字符串为 9,大小就为 9B);不增加或者减少目标文件 inode 的引用计数
  • 在创建软链接时,如果源文件如果使用相对路径,是相对于源文件的路径,而非相对于当前目录,但是软链接的路径如果是相对路径,则是相对于当前工作目录。

格式:

ln -s filename [linkname]

范例:

$ ln -sv /data/f11.txt /data/dir/f11.txt
$ ls -li !*
ls -li -sv /data/f11.txt /data/dir/f11.txt
                     软链接大小跟指向路径有关/data/f11.txt
133 0 lrwxrwxrwx. 1 root root  13 May  7 20:31 /data/dir/f11.txt -> /data/f11.txt
132 4 -rw-r--r--. 1 root root 718 May  7 20:21 /data/f11.txt
# 删除源文件,软链接将无法使用,源文件和软链接有依赖关系。
$ rm -rf /data/f11.txt
$ ls -li /data/dir/f11.txt
133 lrwxrwxrwx. 1 root root 13 May  7 20:31 /data/dir/f11.txt -> /data/f11.txt(源文件失效)
# 可以跨分区的文件实现
$ ln -s /data/dir/f11.txt /opt/f111.txt
$ ls -li -s /data/dir/f11.txt /opt/f111.txt
    133 0 lrwxrwxrwx. 1 root root 13 May  7 20:31 /data/dir/f11.txt -> /data/f11.txt
1877679 0 lrwxrwxrwx. 1 root root 17 May  7 20:34 /opt/f111.txt -> /data/dir/f11.txt
# 可以对目录创建软连接

# 使用绝对路径
ln -sv /data/dir/ /data/dirlink
# 相对路径使用
cd /data/
ln -sv ../data/dir /root/dirlink
rm -rf /data/dirlink    # 删除软连接本身,不会删除源目录内容
rm -rf /data/dirlink/ # 删除源目录的文件,不会输出链接文件

# 查看链接文件指向的源文件
readlink /data/dirlink

$ readlink /proc/1/exe
/usr/lib/systemd/systemd
$ ls -l /proc/1/exe
lrwxrwxrwx. 1 root root 0 May  7 19:53 /proc/1/exe -> /usr/lib/systemd/systemd

3.4 硬链接和软链接区别总结

1 本质:

  • 硬链接:本质是同一个文件
  • 软链接:本质不是同一个文件

2 跨设备:

  • 硬链接:不支持跨设备分区
  • 软链接:支持跨设备分区

3 inode 节点号:

  • 硬链接:相同
  • 软链接:不同

4 链接数:

  • 硬链接:创建新的硬链接,链接数会增加,删除硬链接,链接数会减少
  • 软链接:创建或者删除,链接数不会发生变化

5 文件夹:

  • 硬链接:不支持
  • 软链接:支持

6 相对路径

  • 硬链接:原始文件相对路径是相对于当前工作目录的
  • 软链接:原始文件相对路径是相对于链接文件的相对路径

7 删除源文件

  • 硬链接:只是链接数减一,但是链接文件的访问不受影响
  • 软链接:链接文件将无法访问

8 文件类型

  • 硬链接:和源文件相同
  • 软链接:链接文件,和源文件无关

9 文件大小

  • 硬链接:和源文件相同
  • 软链接:源文件的路径的长度

    3.5 生产案例

    3.5.1 案例1:提示空间满 No space left on device,但是 df 可以看到空间很多,为什么?

    原因有:磁盘空间占满或者是磁盘节点编号占满

    3.5.2 案例2:提示空间快满了,使用 rm 删除了很大的无用文件之后,df 仍然看到空间不足,为什么?如何解决?

  • 先使用 cat /dev/null > /bigfile 将文件清空,后使用 rm -f /bigfile 将文件进行删除。

  • 若已经使用 rm -f /bigfile 删除文件,则使用 lsof | grep delete 查看哪个进程占用了 /bigfile 文件,将该进程号删除。
  • 若进程号是业务进程,则需要等到业务清闲时才能进行删除。
  • 所以,删除文件时,必须先将文件内容清空,再执行删除。

    4 IO重定向和管道

    4.1 标准输入和输出

    程序:指令 + 数据
    读入数据:Input
    输出数据:Output
    打开的文件都有一个fd :file descriptor(文件描述符)
    Linux给程序提供了三种 I/O 设备:

  • 标准输入(STDIN) -0 :默认接受来自终端窗口的输入(键盘,鼠标)

  • 标准输出(STDOUT)-1 :默认输出到终端窗口
  • 标准错误(STDERR) -2 :默认输出到终端窗口
  • 标准输入,标准输出一级标准错误都是由当前终端窗口实现

范例:文件描述符

# 可以在/dev目录下查看到标准
$ ls -l /dev/std*
lrwxrwxrwx 1 root root 15 May  3 20:32 /dev/stderr -> /proc/self/fd/2
lrwxrwxrwx 1 root root 15 May  3 20:32 /dev/stdin -> /proc/self/fd/0
lrwxrwxrwx 1 root root 15 May  3 20:32 /dev/stdout -> /proc/self/fd/1

# 查看进程信息
$ ls -l /proc/self/fd/*
ls: cannot access /proc/self/fd/255: No such file or directory
ls: cannot access /proc/self/fd/3: No such file or directory
lrwx------ 1 root root 64 May  7 21:06 /proc/self/fd/0 -> /dev/pts/0
lrwx------ 1 root root 64 May  7 21:06 /proc/self/fd/1 -> /dev/pts/0
lrwx------ 1 root root 64 May  7 21:06 /proc/self/fd/2 -> /dev/pts/0

$ ls -l /proc/$(pidof tail)/fd
total 0
lrwx------ 1 root root 64 May  7 21:07 0 -> /dev/pts/1
lrwx------ 1 root root 64 May  7 21:07 1 -> /dev/pts/1
lrwx------ 1 root root 64 May  7 21:07 2 -> /dev/pts/1

# 标准输出重定向
$ ls -l > /dev/pts/1 & ls -l 1> /dev/pts/1
# 标准错误重定向
$ ks 2> /dev/pts/1
$ rm f1.txt
rm: remove regular file ‘f1.txt’? # 属于标准错误
# 所谓的错误不一定是真正的错误,有可能是警告或者是报警信息

# 标准输出到其他终端一般会需要root权限

4.2 IO重定向 redirect

I/O 重定向:将默认的输入,输出或者错误对应的设备改变,指向新的目标

4.2.1 标准输出和错误重定向

STDOUT 和 STDERR 可以被重定向到指定文件,而非默认的当前终端
格式:

命令 操作符号 文件名

支持的操作符号包括:

1> 或者 > :把 STDOUT 重定向到文件
>| :强制覆盖
2> :把 STDERR 重定向到文件
&> : 把所有输出重定向到文件
>& :和上面的功能一样,建议使用上面的方式

以上如果文件已经存在,文件内容会被覆盖

set -C:禁止将内容覆盖已有文件,但是可以追加,可以利用 >| 仍然可以强制覆盖
set +C:运行覆盖
>> :可以在原有内容基础上,追加内容

追加

可以在原有内容基础上,追加内容

把输出和错误重新定向追加到文件中

>> :追加标准输出重定向至文件
2>>:追加标准错误重定向至文件

标准输出和错误输出各自定向至不同位置

COMMAND > /PATH/TO/file.out 2> /PATH/TO/error.out

合并标准输出和错误输出为同一个数据流进行重定向

&> :覆盖重定向
&>>:追加重定向

COMMAND > /PATH/TO/file.out 2>&1  (顺序很重要)
COMMAND 2> /PATH/TO/file.out 1>&2 (顺序很重要)
COMMAND >> /PATH/TO/file.out 2>&1

合并多个程序

(CMD1;CMD2;…) 或者 {CMD1;CMD2;…;} 合并多个程序的 STDOUT

范例:

ls 1> /dev/pts/1
ls /data > /dev/pts/1

范例:标准错误重定向

# 根据Shell终端类型有关
rm f1.txt 2> /data/all.log

范例:合并多个命令的结果至一个文件中

( cal 2019;cal 2020 ) > all.txt
{ ls -l;hostname } > all.txt

范例:清除大文件

cat /dev/null > /root/linux/bigfile.img
> /root/linux/bigfile.img

范例:分别重定向

ls -l /data /xxx 1> stdout.log 2> error.log

范例:将标准输出和标准错误都重定向到同一个文件

## 如果没有定义标准输出和标准错误重定向规则,就会默认输出到终端屏幕中
## 2>&1 &为了表示后面的数字代表文件描述符
# ls /data /xxx > /data/all.log 2>&1
# ls /data /xxx 2> /data/all.log 1>&2
# ls /data /xxx &> /data/all.log
# ls /data /xxx >& /data/all.log

## 因为在2>&1 并不知道标准错误是存放在哪里,默认在终端上显示。则标准错误就打印在终端中
# ls /data /xxx 2>&1 > /data/all.log
ls: cannot access /xxx: No such file or directory

范例:

$ man bash > man_bash.txt
$ wc -l man_bash.txt
4200 man_bash.txt

范例:

$ curl http://www.wangxiaochun.com/testdir/hello.sh
#!/bin/bash
# ------------------------------------------
# Filename:     hello.sh
# Version:      1.0
# Date:         2017/06/01
# Author:       wang
# Email:        29308620@qq.com
# Website:      www.wangxiaochun.com
# Description:  This is the first script
# Copyright:    2017 wang
# License:      GPL
# ------------------------------------------
#经典写法
echo "hello, world"
#流行写法
echo 'Hello, world!'

$ curl http://www.wangxiaochun.com/testdir/hello.sh 1> f1.log 2> f2.log
$ ls -l f*
-rw-r--r-- 1 root root 420 May  8 00:01 f1.log
-rw-r--r-- 1 root root 317 May  8 00:01 f2.log
$ cat f1.log
#!/bin/bash
# ------------------------------------------
# Filename:     hello.sh
# Version:      1.0
# Date:         2017/06/01
# Author:       wang
# Email:        29308620@qq.com
# Website:      www.wangxiaochun.com
# Description:  This is the first script
# Copyright:    2017 wang
# License:      GPL
# ------------------------------------------
#经典写法
echo "hello, world"
#流行写法
echo 'Hello, world!'
$ cat f2.log
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100   420  100   420    0     0   3985      0 --:--:-- --:--:-- --:--:--  4000

范例:屏幕不输出修改密码信息

passwd zzw &> /dev/null

范例:实现标准输出和错误的互换

$ (cat /etc/centos-release /etc/xxx 3>&1 1>&2 2>&3) > f1.txt 2> f2.txt
$ cat f1.txt
cat: /etc/xxx: No such file or directory
$ cat f2.txt
CentOS Linux release 7.9.2009 (Core)

4.2.2 标准输入重定向

从文件中导入 STDIN,代替当前终端的输入设备,使用 < 来重定向标准输入某些命令能够接受从文件中导入的 STDIN
所谓的标准输入就是不是通过人为的交互式的方式把输入信息输到计算机程序里面,而是提前准备一个文件,将需要的输入信息写入到文件中,再将该文件导入到标准输入程序
范例:

$ seq -s + 100 > bc.txt
$ bc < bc.txt
5050
# mail 可以给当前机器上的用户发送邮件
$ yum install -y mailx postfix
$ systemctl enable --now postfix

$ mail -s hello zzw
I am root
Hello
.     # (.句号结束)
EOT
# 标准输入重定向
$ cat > mail_template.txt <<-'EOF'
Hello!
I am root
Congratulations! You Login sccessfully
Don't play fire!
EOF
$ mail -s "Give you" zzw < mail_template.txt

### 使用mail实现QQ邮箱发送
# QQ邮箱授权码:yxmomqzszmblbcad
# 需要配置mail配置文件
vim /etc/mail.rc
### 在最后添加以下内容
# 发邮件时 用户的邮箱
set from=935523993@qq.com
# 发邮件时 使用的邮箱服务器地址
set smtp=smtp.qq.com
# 发邮件时 使用的用户
set smtp-auth-user=935523993@qq.com
# 发邮件时 使用的密码(授权码)
set smtp-auth-password=yxmomqzszmblbcad

$ mail -s "Test mail" 935523993@qq.com < mail_template.txt

4.2.2.1 tr 命令

tr 转换和删除字符

tr [OPTION]... SET1 [SET2]

选项:

  • -c -C —complement:取字符集的补集
  • -d —delete:删除所有属于第一字符集的字符
  • -s —squeeze-repeats:把连续重复的字符以一个字符表示,即去重
  • -t —truncate-set1:将第一个字符集对应字符转换为第二字符集对应的字符 ```bash \NNN character with octal value NNN (1 to 3 octal digits) \ backslash \a audible BEL \b backspace \f form feed \n new line \r return \t horizontal tab \v vertical tab

[:alnum:]:字母和数字(all letters and digits) [:alpha:]:字母(all letters) [:cntrl:]:控制(非打印)字符(all control characters) [:digit:]:数字(all digits) [:graph:]:图形字符(all printable characters, not including space) [:lower:]:小写字母(all lower case letters) [:print:]:可打印字符(all printable characters, including space) [:punct:]:标点符号(all punctuation characters) [:space:]:空白字符(all horizontal or vertical whitespace) [:upper:]:大写字母(all upper case letters) [:xdigit:]:十六进制字符(all hexadecimal digits)

范例:
```bash
# 该命令会把/etc/centos-release中的小写字符转换为大写字符
tr 'a-z' 'A-Z' < /etc/centos-release

# 删除fstab文件中的所有abc中的任意字符
tr -d abc < /etc/fstab
$ df
$ df > df.log
$ tr -s " " < df.log

范例:将Windows的文本转化为Linux的文本格式

$ cat windows.txt
a
b
c
windows.txt
$ file windows.txt
windows.txt: ASCII text, with CRLF line terminators
$ hexdump -C windows.txt
00000000  61 0d 0a 62 0d 0a 63 0d  0a 77 69 6e 64 6f 77 73  |a..b..c..windows|
00000010  2e 74 78 74                                       |.txt|
00000014
# windows文本格式与linux文本格式间的转换,windows格式文本中比linux格式文本中多回车键'\r',通过tr删除'\r'实现格式转换
$ tr -d "\r" < windows.txt > windows-linux.txt
$ hexdump -C windows-linux.txt
00000000  61 0a 62 0a 63 0a 77 69  6e 64 6f 77 73 2e 74 78  |a.b.c.windows.tx|
00000010  74                                                |t|
00000011
$ file windows-linux.txt
windows-linux.txt: ASCII text

思考:将Linux的文本转换为 Windows 的文本格式?

注意:不能使用 tr 命令将文件从 Unix 格式转换为 Windows(DOS)。
除此之外Linux还提供了两种文本格式相互转化的命令:dos2unix和unix2dos,dos2unix把"\r\n"转化成"\n",unix2dos把"\n"转化成"\r\n"。

4.2.2.2 标准输入重定向

实现标准输入重定向的符号

COMMAND 0< FILE
COMMAND < FILE

比如:

cat < /etc/centos-release
CentOS Linux release 7.9.2009 (Core)

按 Ctrl + D离开,可以使用文件来代替键盘的输入

cat < file1 > file2
cat < file1 >> file1

范例:

$ echo "2^3" > bc.log
$ bc < bc.log
8

$ cat > mail_template.txt
Hello!
I am root
Congratulations! You Login sccessfully
Don't play fire!
$ cat < mail_template.txt > mail_template2.txt
$ mail -s "Test mail" zzw < mail_template.txt

$ cat > cat.log
line1
line2
line3

4.2.2.3 把多行重定向

使用 “<< 终止词” 命令 从键盘把多行重导向给 STDIN,直到终止词位置之前的所有文本都发送给 STDIN,有时被称为就地文本(here documents)。
其中终止词可以是任何一个或者多个符号,比如:!,@,$,EOF(End Of File),magedu 等等,其中 EOF 比较常用。
范例:

$ mail -s "Please Call" root <<EOF
> Hi wang
>
> Please give me a call when you get in.Wey may need
> to do some maintenance on server1
>
> Details where you're on-site
> Zhong
> EOF
# 查看邮件

4.3 管道

4.3.1 管道

管道(使用符号 “|” 表示)用来连接多个命令;
格式:

命令1 | 命令2 | 命令3 | ......

功能说明:

  • 将命令1 的 STDOUT 发送给命令2 的 STDIN,命令2 的 STDOUT 发送到命令3 的 STDIN;
  • 所有命令会在当前 Shell 进程的子 Shell 进程中执行
  • 组合多种工具的功能

注意:STDERR 默认不能通过管道转发,可以利用 2>&1 或者 |& 实现,格式如下:

命令1 2>&1 | 命令2
命令1 |& 命令2

范例:非交互式修改用户密码

# 方法1
$ passwd --stdin wang
Changing password for user wang.
Admin@h3c
passwd: all authentication tokens updated successfully.

# 方法2
$ echo "Admin@h3c" > wang-password.txt
$ passwd --stdin wang < wang-password.txt

# 方法3:
$ cat wang-password.txt | passwd --stdin wang

# 方法4:
echo "Admin@h3c" | passwd --stdin wang
echo "Admin@h3c" | passwd --stdin wang &> /dev/null

范例:

# 将小写字母转换为大写字母
ls | tr 'a-z' 'A-Z'
# less 实现分页的查看输入
ls -l /etc/ | less
# mail通过电子邮件发送输入
echo "Test mail" | mail -s 'Test mail' 935523993@qq.com
# 算数运算
echo "2^3" | bc

4.3.2 tee 命令

利用 tee 命令可以重定向到多个目标(tee 命令即将输出重定向到文件也将输出的信息显示出来),经常配合管道符一起使用
格式:

命令1 | tee [-a] 文件名 | 命令2

以上可以把命令1 的 STDOUT 保存在文件中,做为命令2 的输入
选项:

  • -a 追加

功能:

  • 保存不同阶段的输出
  • 复杂管道的故障排除
  • 同时查看和记录输出

范例:

echo {1..100} | tr " " + | bc
echo {1..100..2} | tr " " + | bc

seq -s + 100 | bc
seq -s + 1 2 100 | bc

范例:

cat << | tee -a /etc/mail.rc
# 发邮件时 用户的邮箱
set from=935523993@qq.com
# 发邮件时 使用的邮箱服务器地址
set smtp=smtp.qq.com
# 发邮件时 使用的用户
set smtp-auth-user=935523993@qq.com
# 发邮件时 使用的密码(授权码)
set smtp-auth-password=yxmomqzszmblbcad
set smtp-auth=login
set ssl-verify=ignore
EOF
cat <<EOF | tee /etc/motd
> The hostname is kubesphere-docker.io
> Don't play fire!!!
> EOF
The hostname is kubesphere-docker.io
Don't play fire!!!

4.4 重定向中的 - 符号

重定向有时会有使用 - 符号
范例:

# -O 指定下载后的文件名
wget -O hello.sh http://www.wangxiaochun.com/testdir/hello.sh
# - 重定向到当前屏幕中,而非保存到文件中
# - 将保存的文件内容输出到屏幕中,与 > 标准输出相反
wget -O - http://www.wangxiaochun.com/testdir/hello.sh
wget -qO - http://www.wangxiaochun.com/testdir/hello.sh

范例:
将 /home 里面的文件打包,但是打包的数据不是记录到文件,而是传送到 stdout,经过管道后,将 tar -cvf - /home 传送给后面的 tar -xvf -,后面的这个 - 则是取前面一个命令的 stdout,因此,就不需要使用临时的file了

# 原始命令
tar -cvf home.tar /home ; tar -xvf home.tar
# 少个中间的产物
tar -cvf - /home | tar -xvf -

4.5 练习

# 1、将/etc/issue文件中的内容转换为大写后保存至/tmp/issue.out文件中
# 2、将当前系统登录用户的信息转换为大写后保存至/tmp/who.out文件中
# 3、一个linux用户给root发邮件,要求邮件标题为”help”,邮件正文如下:
# 4、将/root/下文件列表,显示成一行,并文件名之间用空格隔开
# 5、计算1+2+3+...+99+100的总和
# 6、删除Windows文本文件中的回车字符 ,即“\r”
# 7、处理字符串“xt.,l 1 jr#!$mn 2 c*/fe 3 uz 4”,只保留其中的数字和空格
# 8、将PATH变量每个目录显示在独立的一行
# 9、将指定文件中0-9分别替代成a-j
# 10、将文件/etc/centos-release中每个单词(由字母组成)显示在独立一行,并无空行
# 1、将/etc/issue文件中的内容转换为大写后保存至/tmp/issue.out文件中
# 方法1:
$ cat /etc/issue | tr -s [:lower:] [:upper:] > /tmp/issue.out
$ cat /tmp/issue.out
\S
KERNEL \R ON AN \M
# 方法2:
$ tr "a-z" "A-Z" < /etc/issue > /tmp/issue.out

# 2、将当前系统登录用户的信息转换为大写后保存至/tmp/who.out文件中
$ who | tr -s [:lower:] [:upper:] > /tmp/who.out

# 3、一个linux用户给root发邮件,要求邮件标题为”help”,邮件正文如下:
## Hello, I am 用户名,The system version is here,please help me to check it ,thanks!
## 操作系统版本信息
# 方法1:
$ vim mail.txt
Hello,
I am $(whoami),The system version is here,please help me to check it ,thanks!
$(cat /etc/os-release)
$ mail -s 'help' root < mail.txt

# 方法2: 
$ cat <<EOF | mail -s 'help' root
> Hello,
> I am `whoami` ,The system version is here,please help me to check it ,thanks!
> `cat /etc/centos-release`
> EOF

# 4、将/root/下文件列表,显示成一行,并文件名之间用空格隔开
$ ls -l /root/ | tr -s "\n" " "
$ ls /root | tr -s "\n" " "

# 5、计算1+2+3+...+99+100的总和
# 方法1:
$ echo {1..100} | tr -s " " + | bc
5050
# 方法2:
$ seq -s "+" 100 | bc
5050

# 6、删除Windows文本文件中的回车字符 ,即“\r”
$ file windows.txt
windows.txt: ASCII text, with CRLF line terminators
$ hexdump -C windows.txt
00000000  77 69 6e 64 6f 77 73 0d  0a 61 0d 0a 62 0d 0a 63  |windows..a..b..c|
00000010
$ tr -d "\r" < windows.txt > linux.txt
$ hexdump -C linux.txt
00000000  77 69 6e 64 6f 77 73 0a  61 0a 62 0a 63           |windows.a.b.c|
0000000d

# 7、处理字符串"xt.,l 1 jr#!$mn 2 c*/fe 3 uz 4",只保留其中的数字和空格
$ echo "xt.,l 1 jr#!$mn 2 c*/fe 3 uz 4" | tr -dc "0-9 "
$ echo "xt.,l 1 jr#)mn 2 c*/fe 3 uz 4" | tr -dc [0-9][[:space:]]
$ echo "xt.,l 1 jr#windows.txtmn 2 c*/fe 3 uz 4" | dc "[[:digit:][:space:]]"

# 8、将PATH变量每个目录显示在独立的一行
$ echo $PATH | tr -s ":" "\n"

# 9、将指定文件中0-9分别替代成a-j
$ echo "1234567890987654321" > number.txt
$ tr "0-9" "a-j" < number.txt

# 10、将文件/etc/centos-release中每个单词(由字母组成)显示在独立一行,并无空行
$ cat /etc/centos-release | tr -s " " "\n" | tr -dc "a-zA-Z\n"
CentOS
Linux
release