# 文件处理

# 文件路径

# basename

$ basename <path>     # 获得一个路径的最后一段的名字
           [suffix]   # 去掉后缀
  • 不会检查输入的路径是否实际存在。
  • 例:
    [root@CentOS ~]# basename /root/test.py .py
    test
    

# dirname

$ dirname <path>...   # 获得路径所属的目录
  • 如果输入的路径不包含 / ,则视作位于当前目录。
  • 例:
    [root@CentOS ~]# dirname f1 /tmp
    .
    /
    

# realpath

$ realpath <path>...    # 将路径转换成绝对路径
  • 例:
    [root@CentOS ~]# realpath f1 /tmp
    /root/f1
    /tmp
    

# 查看文件

# ls

$ ls [path]     # 列出指定目录(默认为当前目录)下的各个文件名(不包括隐藏文件)
      -a        # 显示所有文件(包括隐藏文件)
      -A        # 与 -a 相比,不显示相对目录 . 和 ..
      -l        # 显示文件的详细信息
      -h        # 以人类容易阅读的单位显示文件大小
      -d        # 只显示目录本身,不显示目录下的内容
      -i        # 显示文件指向的 inode 号
      -Z        # 增加显示一列安全上下文,格式为 user:role:type:level
      -S        # 按文件的大小排序
      -t        # 按文件的 modify time 排序
  • 例:
    [root@CentOS ~]# ls -al
    total 64
    dr-xr-x---.  7 root root   4096 Nov 27 19:17 .
    dr-xr-xr-x. 18 root root   4096 Oct 10 02:49 ..
    -rw-------   1 root root   6318 Dec  1 15:44 .bash_history
    -rw-r--r--.  1 root root     18 Dec 29  2013 .bash_logout
    -rw-r--r--.  1 root root    176 Dec 29  2013 .bash_profile
    -rw-r--r--.  1 root root    176 Dec 29  2013 .bashrc
    
    • total 表示已显示的这些文件占用的磁盘 block 总数。
    • 第一列,比如 dr-xr-x---. ,开头的 d 表示文件类型为目录,其后的 r-xr-x--- 表示文件的访问权限,末尾的 . 表示该文件使用了 SELinux 。(如果使用了 ACL 就会变成 + )
    • 第二列的数字表示指向该文件的 inode 的硬链接数。
    • 第三列、第四列表示文件所有者、所有者所属用户组。
    • 第五列表示文件的大小(单位为 Byte)。如果该文件是目录,则不包括目录中各文件的大小。
    • Nov 27 19:17 表示文件的最后修改时间。
    • 最后一列表示文件名。
  • 查询文件路径时,可使用以下匹配符号:
    [root@CentOS ~]# touch f1 f2 f3
    [root@CentOS ~]# ls f*          # 通配符 * 匹配任意个字符(包括零个)
    f1  f2  f3
    [root@CentOS ~]# ls ?1          # 通配符 ? 匹配单个字符
    f1
    [root@CentOS ~]# ls [a-z][0-2]  # 模式匹配在字符集中的单个字符。 [a-z] 不区分大小写,而 [abc] 区分大小写
    f1  f2
    

# du

$ du [path]... # 显示指定目录(默认为当前目录)及其子目录下的各个文件占用的磁盘空间
      -a       # 增加显示非目录文件
      -h       # 以人类容易阅读的单位显示文件大小
      -d n     # 最多显示 n 层子目录
      -s       # 只显示该目录占用的总磁盘空间
  • 例:
    du -ahd 1   # 显示当前目录下各个文件的大小,像 Windows 风格
    

# tree

$ tree [path]...   # 按树形结构显示某个目录(默认为当前目录)下的所有文件
       -a          # 增加显示隐藏文件
       -C          # 采用不同颜色显示不同类型的文件
       -L <n>      # 最多显示到第 n 层子目录
       -D          # 显示每个文件的最后修改时间
       -p          # 显示每个文件的访问权限
       -u          # 显示每个文件的所有者
       -sh         # 以人类容易阅读的单位显示文件大小
  • 安装: yum install tree

# lsof

$ lsof             # 显示目前所有被进程打开的文件
      <filename>   # 显示打开指定文件的所有进程
      -p <pid>     # 显示指定进程打开的所有文件
      -u <uid>     # 显示指定用户打开的所有文件

      -i           # 只显示 socket 文件
      -i :22       # 只显示指定端口的 socket 文件
  • 安装:yum install lsof

# 查找文件

# find

$ find [path]               # 显示指定目录(默认是当前目录)下的所有文件(包括子目录)
        # 可选添加以下选项作为筛选条件
        -maxdepth 1         # 限制搜索的目录深度(默认为无限深)
        -type f             # 限制文件类型,类型可以是 f、d、l、s、c 等
        -empty              # 筛选出内容为空的文件或目录

        -name *.py          # 筛选文件名,采用 shell 风格的匹配
        -iname *.py         # 匹配时不区分大小写(insensitive)
        -path */test/*      # 筛选文件路径
        -ipath */test/*
        -regex .*py         # 筛选文件路径,采用正则匹配
        -iregex .*py

        -user root          # 属于指定用户的文件,可以使用 uid
        -group root         # 属于指定用户组的文件,可以使用 gid
        -perm <mode>        # 文件权限等于 mode ,mode 取值可以为 0644、644、u=rw-,g=rw,o=r 等格式,按二进制位进行匹配
        -perm -<mode>       # 文件权限大于 mode

        -size -10k          # 小于 10k 的文件
        -amin -3            # 过去 3 分钟之内被 access 的文件(同理还有 cmin、mmin )
        -atime -3           # 过去 3 天之内被 access 的文件(同理还有 ctime、mtime )

        # 可选对找到的每个文件执行一个动作
        -exec echo {} \;    # 执行一条命令,该命令以 \; 结尾,用 {} 嵌入文件名
        -delete             # 删除文件
  • 筛选条件为数值类型时,有三种表示方式:
    n     # 等于
    +n    # 大于
    -n    # 小于
    
  • -size 选项可以使用以下单位:
    b     # blocks ,默认采用这种
    c     # bytes
    k     # kilo bytes
    M     # Mega bytes
    G     # Giga bytes
    
  • 例:
    [root@CentOS ~]# touch 1.py
    [root@CentOS ~]# ls -al
    total 8
    drwxrwxr-x.  2 root root   28 Jan  8 11:10 .
    drwx------. 14 root root 4096 Jan  8 10:52 ..
    -rw-rw-r--.  1 root root    0 Jan  8 11:10 1.py
    [root@CentOS ~]# find . -name *.py
    ./1.py
    [root@CentOS ~]# find . ! -name *.py            # 在筛选条件之前加冒号 ! 则表示反选
    .
    [root@CentOS ~]# find . ! -name *.py ! -name .  # 可以重复使用同一种筛选条件
    [root@CentOS ~]# touch 2.py
    [root@CentOS ~]# find . -name *.py    # 通配符 *  可能匹配当前目录下的文件,这里命令被解析成 find . -name 1.py 2.py ,需要加上引号定界符 find . -name '*.py'
    find: paths must precede expression: 2.py
    
  • 例:查找并删除文件时,有多种命令写法
    find . -name *.log -delete
    find . -name *.log -exec rm -f {} \;
    find . -name *.log | xargs -n 1 rm -f
    

# locate

$ locate [pattern]  # 显示文件路径包含 pattern 的所有文件
         -i         # pattern 不区分大小写
         -r         # pattern 采用正则表达式
  • 安装: yum install mlocate
  • locate 命令会从数据库 /var/lib/mlocate/mlocate.db 中查找文件,速度较快。该数据库一般每天更新一次,执行命令 updatedb 可立即更新。

# 移动文件

# rename

$ rename <源字符串> <目标字符串> <文件>...   # 替换文件名中的字符串
         -v                                # 显示每个被处理的文件
  • rename 命令主要用于批量重命名文件,不能像 mv 命令一样移动文件。

# mv

$ mv <src_path>... <dst_path> # 移动文件或目录
     -f     # 如果目标文件已存在,则覆盖它
     -i     # 如果目标文件已存在,则提示用户是否进行覆盖
     -u     # 当目标文件不存在,或源文件比目标文件新时,才执行移动(即 update)
  • mv 命令可以用于移动文件,也可以用于重命名文件(此时源路径只能有一个)。
    • 如果 dst_path 已存在且是一个文件,则考虑是否覆盖目标文件。
    • 如果 dst_path 已存在且是一个目录,则会将 src_path 移动到该目录之下。
    • 如果是在同一文件系统内 mv 文件,则只会重命名文件路径,依然使用源文件的 inode 号 。
    • 如果是跨文件系统 mv 文件,则会先拷贝源文件到目标路径(使用新的 inode 号),再删除源文件,相当于 cp f1 f2 && rm f1
      • 如果 mv 文件、文件夹的过程失败,并不会删除源文件。
  • 假设在同一文件系统内操作:
    • mv f1 f2
      • 如果 f2 不存在,则会将 f1 重命名为 f2 ,依然使用 f1 的 inode 号。
      • 如果 f2 已存在,则会先删除 f2 ,再将 f1 重命名为 f2 ,依然使用 f1 的 inode 号。
    • mv dir1/ dir2/
      • 如果 dir2 不存在,则将 dir1 重命名为 dir2 。
      • 如果 dir2 已存在,则将 dir1 移动到 dir2 之下,保存为 dir2/dir1 。
      • 如果 dir2/dir1 已存在且不为空,则会报错 cannot move 'dir1' to '/dir2/dir1': Directory not empty ,此时可以改用 cp -rf dir1 dir2 && rm -rf dir1
    • mv dir1/* dir2/
      • 将 dir1/ 目录下的所有文件移动到 dir2/ 目录下。
      • 当移动多个源文件时,目标路径只能是一个目录,因此末尾不加斜杆 / 也能自动识别。

# rm

$ rm <path>...  # 删除文件
     -d         # 删除目录(只能是空目录)
     -r         # 递归删除(用于删除非空目录)
     -i         # 若文件存在,则提示用户是否确认删除
     -f         # 强制删除(覆盖 -i 选项,且忽略文件不存在时的报错)
     -v         # 打印正在删除的文件列表
  • 例:
    rm -rfv *     # 强制删除当前目录下的所有文件
    

# 切割文件

# split

$ split [file] [prefix]   # 默认每隔 1000 行分割出一个子文件,子文件按 xaa、xab、xac 的格式命名,其中 prefix 默认为 x
        -l 10             # --lines ,每隔 10 行分割出一个子文件
        -b 10K            # --bytes ,每隔 10K Bytes 分割出一个子文件,单位可以是 K、M、G、T 等
        -d                # 让子文件从数字 00 开始编号
        --additional-suffix=.txt  # 给分割出的每个子文件,添加文件扩展名
  • 例:
    [root@CentOS ~]# split -l 3 -d README.md README.md-
    [root@CentOS ~]# ls
    README.md  README.md-00  README.md-01  README.md-02  README.md-03  README.md-04
    [root@CentOS ~]# cat README.md-* > merged
    

# csplit

$ csplit [file] [pattern]...  # 根据 pattern 分割文件。分割出的文件默认按 xx00、xx01、xx02 的格式命名
        -f xx                 # 设置子文件名称的前缀,默认为 xx
        -k                    # --keep-files ,当执行出错时,保留已生成的子文件。默认会全部删除
        -s                    # --silent ,不打印每个子文件的 bytes 体积。默认会打印
        --suppress-matched    # 保存子文件时,排除匹配行
  • 例:
    csplit f1  2          # pattern 为数字时,表示从第 n 行分割出两个子文件,并且第 n 行保存到后一个子文件
    csplit f1  3 6 9      # 可指定多个 pattern ,这会分割多次
    csplit f1  /Hello/    # 寻找与 pattern 正则匹配的行,从每个匹配行分割文件,并且每个匹配行保存到后一个子文件
    csplit f1  %^Hello%   # %pattern% 表示排除匹配行之前的内容,将从匹配行开始的内容保存为子文件
    csplit f1  "/^Hello World/" {5}   # {n} 表示将前一个 pattern 重复执行 n 次,如果找不到匹配行则报错
    csplit f1  "/^Hello World/" {*}   # {*} 表示将前一个 pattern 重复执行尽可能多次,直到找不到匹配行。至少会生成一个子文件
    

# truncate

$ truncate [file]...  # 将文件截断为指定大小。多余的空间会被丢弃,缺少的空间会用空字节填充
          -s 10M      # 保留从文件第一个字节开始的 10M 内容

# 其它

# md5sum

$ md5sum [file]...    # 计算文件内容的 md5 哈希值
  • 例:
    [root@CentOS ~]# echo Hello | md5sum
    09f7e02f1290be211da707a266f153b3  -
    
  • 当文件内容改变任一字节时,哈希值都会变化。但文件属性(比如修改时间)变化时,哈希值不变。
  • 另外还有 sha1sum、sha256sum、sha512sum 等其它哈希算法的命令,用法同理。

# 随机数

  • 类 Unix 系统会收集一些环境噪声(比如硬件中断的时间戳的最低几位),暂存到一个熵池(entropy pool)中,用于生成随机数。
  • 查看系统熵池的大小,单位为 bits :
    [root@CentOS ~]# cat /proc/sys/kernel/random/entropy_avail
    3754
    
  • 用户可通过以下两个字符设备文件,获取随机数:
    • /dev/random :消耗熵池来产生随机数,随机性很高,但是熵池不足时会阻塞读取它的进程。
    • /dev/urandom :重复使用熵池来产生随机数,随机性略低,但一般足够安全。一般读取速度为几十 MB/s ,不会阻塞。
    • 例:
      head -c 10m /dev/urandom > f1                            # 生成一个指定大小、随机内容的文件
      cat /dev/urandom | tr -cd 0-9A-Za-z | head -c 12 ; echo  # 生成随机字符串
      echo $[`cat /dev/urandom | tr -cd 0-9 | head -c 2`%5]    # 生成小于 5 的随机数