1. Linux文件管理

192 阅读10分钟

本系列都是是基于RedHat体系的,所以CentOS也可以用,但是Debian系列的可能会有些命令上的出入。

1. 文件

1.1 文件目录长格式解释

$ ls -l
-rw-------. 1 root root 1428 Jan 11 10:22 ks.cfg
  • 文件类型:第一个字母,文件种类有很多,因为Linux中沿袭了Unix的哲学:一切皆文件。但是linux的文件后缀名和文件类型没有关系,例如执行权限就可以执行,但是不一定执行成功罢了。单一文件或目录的最大容许文件名为255字节,大约是255个字符的长度。
    • 普通文件-
      • 纯文本文件ASCII UTF-8
      • 二进制文件binary
    • 目录d directory
    • 符号链接文件l link
    • 设备文件b|c
      • 区块设备文件b block,例如/dev/sda,随机访问,按数据块访问,大小是两个数存储于inode中,第一个是主设备号major number标识设备类型,第二个是次设备号minor number标识同一种类型中不同设备;
      • 字符设备文件c character,线性访问,按字符为单位
      • mknod [OPTION] ... NAME TYPE [MAJOR MINOR]创建block或character特殊文件
        • -m:指定权限
    • 数据接口文件s socket,如常在/run/tmp目录中看到
    • 数据输送档p FIFO,pipe
  • 文件权限:类型后9个字符rw-r--r--,分别是u g o的权限,rwx,分别是读、写和执行权限,位置不会变,-是无该权限;
  • 硬连接数:是硬连接数,连接到该文件的数量;
  • 属主:owner,文件拥有者,这里是root
  • 属组:group,文件所属群组,这里是root
  • 文件大小:size,默认单位是字节,使用-h可以变为人类友好显示;
  • 时间戳:timestamp,创建日期或者最近修改日期,显示完整时间需要ls -l --full-time
    • 访问(access):
    • 修改(modify):文件自身数据修改时间
    • 改变(change):metadata,文件属性数据改变时间
  • 文件名/目录名

1.2 文件目录配置标准--FHS

Filesystem Hierarchy Standard,FHS针对目录树结构仅定义了三层目录放置什么数据,各个目录下面又有明确的说明:

  1. / (root,根目录):与系统开机/还原/修复等有关。所有的目录都由根目录衍生出来,根目录不建议放在很大的分区,分区越大放入数据越多,错误机会越高,但同时也要能够容纳足够的修复文件系统的程序;
  2. /usr(unix software resource):与软件安装执行相关;【basil:原来usr不是user的缩写,而是UNIX软件资源】
  3. /var(variable):与系统运行过程有关。
可分享的(shareable)不可分享的(unshareable)
不变的(static)/usr(软件放置处)
/opt(第三方软件)
/etc(配置文件)
/boot(开机与核芯文档)
可变的(variable)/var/mail(使用者邮件邮箱)
/var/spool/news(新闻群组)
/var/run(程序相关)
/var/lock(程序相关)
/						  # 根目录
├── bin -> usr/bin		# 最经常使用的用户命令
├── boot				# 系统启动相关文件,如内核vmlinuz、文件系统initramfs、grub:boot loader
├── dev					# 设备文件,没有大小,只有metadata,分为主设备号和次设备号
├── etc					# 配置文件目录和子目录,纯文本格式
├── home				# 用户家目录,默认为/home/$USER
├── lib -> usr/lib		# 最基本的动态连接共享库
│   ├── modules		   # 内核模块文件
├── lost+fount			# 一般是空的,非法关机(例如突然断电)后才会有文件
├── media				# 移动设备挂载点,如U盘,光驱,会自动挂载
├── mnt					# 用户临时需要挂载的文件系统
├── opt					# 可选目录,早期用于安装第三方软件,现在安装到了/usr/local,额外安装软件的目录,例如Oracle
├── proc				# 虚拟目录,系统内核映射文件,系统调优相关的目录
├── root				# root用户家目录
├── sbin -> usr/sbin	# s是Super User的意思,是管理员使用的命令目录,和系统管理相关
├── sys					# 也是虚拟目录, 跟硬件设备相关的属性映射文件, 也和系统调优相关
├── tmp					# 临时文件, 每个人都有权限操作, 只能删除自己的, 其中文件每隔一段时间自动清除
├── usr					# Universal Shared Readonly, 用户安装的很多软件和文件目录.
│   ├── bin				# 普通用户使用的普通命令,当然root用户也可用
│   ├── lib
│   ├── sbin
│   ├── src				# 内核源码
│   ├── local			# 第三方软件的安装路径
│   │   ├── bin
│   │   ├── lib
│   │   ├── sbin
├── var					# 不断扩充的目录,例如日志
│   ├── cache		    # 缓存
│   ├── lock			# 锁
│   ├── log				# 日志
│   ├── run				# 存储PID
│   ├── tmp				# 临时文件目录

1.3 文件

1.3.1 命名规则

  1. 长度不能超过255个字符
  2. 不能使用/当文件名, 其它字符都可以
  3. 严格区分大小写

1.3.2 FD简介

file descriptors,FD,文件描述符,文件句柄,进程使用fd来管理打开的文件。是8位的整数(0~255)

  • 0:stdin,标准输入
  • 1:stdout,标准输出
  • 2:stderr,标准错误输出

1.4 操作

1.4.1 目录操作

$ cd
$ ls
$ pwd
$ mkdir	# -p,创建多级目录
$ rmdir # 删除空目录,-p:递归式的删除路径上的空目录
$ tree	# 以树状图列出文件和目录,-d只显示目录
$ du	# disk use,查看当前目录下各个目录的大小, -h:human,-s:指定本路径目录大小
$ df	# disk free,磁盘使用情况,-h:human,-i:inode

1.4.2 文件操作

$ touch <name> 		# 如果已经存在,将会修改最后一次的修改日期,否则就是创建文件,-c指定不创建,-m/-a只修改modify/access时间
$ od	# 获取`二进制`文件信息: -t 指定数据的显示格式,c:ASCII字符,d:有符号十进制数,f:浮点数,o:八进制数,u:无符号十进制数,x:十六进制数
$ wc	# word count,统计`文本`文件信息:   -l行 -w单词 -m字符 -c字节数,-L最长行字符数
$ cat	# -b,只给非空文本编号,-n给所有行都编号, -E每行尾加一个`$`
$ tac	# 反过来显示文件的内容,就是第一行显示文件的最后一行
$ head	# -n <num> -<num>,两个是相同的
$ tail	# -f实时更新显示内容,监控日志文件
$ less
$ more
$ cut	# 剪切文件, -d<delimiter>字段分割符,默认是空格,-f<num>第几列字段,-f 1,3 -f 1-3
$ join	# 连接
$ sort	# 文本排序,默认字符升序,-n数值大小排序,-r逆序排序,-t指定字段分隔符,-k根据某个字段排序,-u去相邻重复行unique,-f忽略字符大小写
$ uniq	# unique,报告不显示相邻重复行,-d只显示相邻重复行,-D显示所有相邻重复行,-c显示某行重复次数
$ tr	# 字符处理命令,转换或删除字符,`tr 'ab' 'AB'`,可以结合输入重定向或者管道使用,-d删除出现在字符集中的所有字符
$ sed
$ awk
$ grep

# 可以多个文件拷贝到一个目录,只有最后一个才是dst,前面的都是src
# 如果dst是目录,则拷贝过去,如果是文件则拷贝并重命名
$ cp <src> <dst>	# -f强制覆盖,-i覆盖文件前提示,-r复制目录, -p不改变mode(权限),owner(属主属组),timestamp(时间戳)
$ install <s> <d>   # 拷贝文件设置属性,类似`cp`,-d创建目录,-m指定权限,默认权限是rwxr-xr-x
$ mv <s> <d>	    # -i,覆盖前提示,可以用于重命名
$ rm <name>			# -r,递归删除目录,-f强制删除
$ stat <name>		# 文件metadata信息,如access/modify/change时间

1.5 grep

1.5.1 简介

根据模式搜索文本,并将符合模式的文本行显示出来。

# -i				忽略大小写
# --color			带有颜色
# -v				反向查找,显示不被模式匹配的行
# -o				只显示模式匹配的字符串,每个串显示一行
# -E				使用扩展的正则表达式
# -A NUM			after, 显示匹配行之后的NUM行也显示
# -B NUM			before, 显示匹配行之前的NUM行也显示
# -C NUM			context, 显示匹配行前后的NUM行也显示
$ grep [OPTIONS] PATTERN [FILE...]

1.5.2 正则表达式

  • 元字符:

    • .: 匹配任意单个字符
    • []: 匹配指定范围内的任意单个字符
    • [^]:匹配指定范围外的任意单个字符
    • 字符集合:[:digit:], [:lower:], [:upper:], [:punct:], [:space:], [:alpha:], [:alnum:]
  • 匹配次数(贪婪模式):

    • *: 匹配其前面的字符任意次
    • .*: 任意长度的任意字符
    • \?: 匹配其前面的字符1次或0次
    • \{m,n\}:匹配其前面的字符至少m次,至多n次;n不写表示至少m次,m不能不写。
  • 位置锚定:

    • ^: 锚定行首,此字符后面的任意内容必须出现在行首
    • $: 锚定行尾,此字符前面的任意内容必须出现在行尾
    • ^$: 空白行
    • \<\b: 锚定词首,其后面的任意字符必须作为单词首部出现
    • \>\b: 锚定词尾,其前面的任意字符必须作为单词的尾部出现
  • 分组:

    • \(\):把内容分组,举例:\(ab\)*ab是一个整体出现任意次

    • 分组引用:\<num>: 引用第<num>个左括号以及与之对应的右括号所包括的所有内容。

      $ grep 'l..e.*l..e' test.vim
      He loves his lover.
      She likes her lover.
      He likes his liker.
      She loves her liker.
      $  grep '\(l..e\).*\1' test.vim
      He loves his lover.
      He likes his liker.
      

1.5.3 egrep==grep -E

正则表达式分为两类:Basic REGEXP以及Extended REGEXP。

基本的正则表达式见上面,扩展的正则表达式:

  • 字符匹配

    • .: 匹配任意单个字符
    • []: 匹配指定范围内的任意单个字符
    • [^]:匹配指定范围外的任意单个字符
  • 次数匹配

    • *: 匹配其前面的字符任意次
    • ?: 匹配其前面的字符只有一次
    • +: 匹配其前面的字符至少一次
    • {m, n}:指定次数
  • 位置锚定

    • ^: 锚定行首,此字符后面的任意内容必须出现在行首
    • $: 锚定行尾,此字符前面的任意内容必须出现在行尾
    • ^$: 空白行
    • \<\b: 锚定词首,其后面的任意字符必须作为单词首部出现
    • \>\b: 锚定词尾,其前面的任意字符必须作为单词的尾部出现
  • 分组

    • ():把内容分组,举例:(ab)*ab是一个整体出现任意次
    • 分组引用:\<num>: 引用第<num>个左括号以及与之对应的右括号所包括的所有内容。
  • 或者:|,OR

    • 举例:C|cat表示Ccat

    • 举例:(C|c)at表示Catcat

      $ egrep '\<([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\>' /etc/sysconfig/network-scripts/ifcfg-ens32  --color
      IPADDR=192.168.141.128
      GATEWAY=192.168.141.2
      NETMASK=255.255.255.0
      DNS1=101.6.6.6
      
      # ifconfig中的IP地址
      [root@localhost ~]# ifconfig | egrep -o '\<([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\>\.\<([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\>\.\<([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\>\.\<([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\>'
      192.168.141.128
      255.255.255.0
      192.168.141.255
      127.0.0.1
      255.0.0.0
      
      # 简化一点
      [root@localhost ~]# ifconfig | egrep -o '(\<([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5]\>)\.){3}\<([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\>'
      192.168.141.128
      255.255.255.0
      192.168.141.255
      127.0.0.1
      255.0.0.0
      

1.5.4 fgrep

不支持正则表达式,速度比较快,只支持根据字符本身来匹配。

1.7 sed

数据流编辑器,Stream EDitor。是一个行编辑器,操纵文本,类似vim。通过模式匹配可以指定要编辑的行,要在模式空间进行处理,所以不会处理原文本,模式空间中处理结果显示在屏幕或者输出重定向。“模式-匹配-显示”。

man sed可以显示其文档。使用sed的基本格式是:sed [OPTIONS] 'AddressCommand' file ...

  • 常用OPTIONS
    • -n:静默模式,不会再默认显示模式空间中的内容。
    • -i:直接修改原文件
    • -e SCRIPT1 -e SCRIPT2:可以同时执行多个sed脚本,每个AddressCommand称为一个脚本
    • -f /path/to/SCRIPT:指定sed脚本文件
    • -r:使用扩展的正则表达式
  • Address的格式
    • StartLine,EndLine1,100表示第1到100行,$表示最后一行;
    • /RegExp//^root/表示以root开头的行;
    • /pattern1/,/pattern2/表示从第一次被/pattern1/匹配行开始,从第一次被/pattern2/匹配行结束;
    • LineNum表示指定匹配某一行;
    • StartLine,+N表示从指定行开始,向后的N行,共N+1行。
  • Command常用
    • d:删除某一行;
    • p:显示符合条件的行;
    • a \"string":在指定的行后面追加新行,内容为"string",换行符为\n
    • i \"string:在指定的行前面追加新行,内容为"string",换行符为\n
    • r FILENAME:将FILENAME中的内容添加到符合条件的行数;
    • w FILENAME:将指定范围地址的行内容另存至指定的文件中;
    • s/pattern/string/[g|i]:将pattern第一次匹配的内容替换为string,如果全部替换,最后加上gi表示忽略大小写;这里/可以替换成大部分符号,只要三个一致即可,如s###s@@@;这里可以使用后向引用\(\)\1,或者&表示匹配到的内容;

练习

  1. 删除/etc/grub.conf文件中行首的空白符; sed -r 's@^[[:spapce:]]+@@g' /etc/grub.conf
  2. 替换/etc/inittab文件中"id:3:initdefault:"一行中的数字为5; sed 's@\(id:\)[0-9]\(:initdefault:\)@\15\2@g' /etc/inittab
  3. 删除/etc/inittab文件中的空白行; sed '/^$/d' /etc/inittab
  4. 删除/etc/inittab文件中开头的#号; sed 's@^#@@g' /etc/inittab
  5. 删除某文件中开头的#号及后面的空白字符,但要求#号后面必须有空白字符; sed -r 's@^#[[:space:]]+@@g' /etc/inittab
  6. 删除某文件中以空白字符后面跟#类的行中的开头的空白字符及# sed -r 's@^[[:space:]]+#@@g' /etc/inittab
  7. 取出一个文件路径的目录名称; echo "/etc/rc.d/" | sed -r 's@^(/.*/)[^/]+/?@\1@g' 基名: echo "/etc/rc.d/" | sed -r 's@^/.*/([^/]+)/?@\1@g'

1.8 awk

报告文本生成器,也是文本处理工具。指定分割符,显示对应段。同sed按照行进行处理,按照分割符分割,逐段命名$1, $2,...

awk [options] 'script' file1 file2, ...

awk [options] 'PATTERN { action }' file1 file2, ...

ACTION

  1. '{print ARG1, ARG2, ...}'这里必须使用''单引号引起来,而且要分开不同的项目需要使用逗号,,输出的参数可以为字符串或数值、当前记录的字段(如$1)、变量或awk的表达式;数值会先转换为字符串,而后再输出;print命令后面的参数可以省略,此时其功能相当于print $0,因此,如果想输出空白行,则需要使用print ""

OPTIONS

  1. -F[src_delimer]:指定输入文件的分割符,awk -F: '{print $1}' /etc/passwd

2. 文件查找

2.1 find

实时、精确,遍历指定目录中的所有文件完成查找,速度相对较慢。

支持更多的查找动作。

格式

# find [path] [options] [expression] [action]
# find 路径 选项 描述(表达式) 动作

默认路径是当前目录,默认查找当前路径下所有文件,处理动作默认为显示。

2.1.1 选项

  1. -name FILENAME:查找对应文件名,可以带有*表示通配符

    $ find /etc -name "hosts"
    /etc/hosts
    /etc/avahi/hosts
    $ find /etc -name "hos*"
    /etc/hosts
    /etc/hostname
    /etc/avahi/hosts
    /etc/hosts.deny
    /etc/host.conf
    /etc/hosts.allow
    
  2. -i FILENAME:ignorecase, 不区分文件名大小写

    $ find /etc -iname "HOsTs"
    /etc/hosts
    /etc/avahi/hosts
    
  3. -regex PATTERN:基于正则表达式进行查找

  4. -user USER:根据文件的属主进行查找

    $ find /home -user basil | head -5
    /home/basil
    /home/basil/.dbus
    /home/basil/.dbus/session-bus
    /home/basil/.dbus/session-bus/eac7fd31fc9f4be68dff626700348d61-0
    /home/basil/blog
    
  5. -group GROUP:根据文件的属组进行查找

    $ find /home -group basil | head -2
    /home/basil
    /home/basil/.dbus
    
  6. -nouser:查找没有属主的文件

  7. -nogroup:查找没有属组的文件

  8. -size: 文件大小,+代表大于,-代表小于,没有则是相等

    $ find /var -size +5M | head -1
    /var/log/journal/eac7fd31fc9f4be68dff626700348d61/system@77d1c20970364741a4fabff259eab144-00000000000186be-0005b1aa06e464e6.journal
    $ find /var -size  5M | head -1
    /var/cache/apt/archives/mysql-client-core-8.0_8.0.22-0ubuntu0.20.04.3_amd64.deb
    $ find /var -size -5M | head -1
    /var
    
  9. -type FILETYPE:-type:按照文件类型来查找

    $ find /dev -type l | head -2
    /dev/v4l/by-path/pci-0000:00:1d.0-usb-0:1.4:1.0-video-index0
    /dev/v4l/by-path/pci-0000:00:1d.0-usb-0:1.4:1.0-video-index1
    $ find /dev -type b | head -2
    /dev/sdb
    /dev/sr0
    $ find /dev -type c | head -2
    /dev/media0
    /dev/video1
    $ find /dev -type - | head -2
    find: Unknown argument to -type: -
    $ find /dev -type d | head -2
    /dev
    /dev/v4l
    $ find /etc -type f | head -2
    /etc/xdg/libfm/libfm.conf
    /etc/xdg/ui/ui_standards.rc
    
  10. -maxdepth:几级目录

    $ find / -maxdepth 2 -a -name host*
    /etc/hosts
    /etc/hostname
    /etc/hosts.deny
    /etc/host.conf
    /etc/hosts.allow
    
  11. 连接两个选项,-a 是and与,默认即是and,-o是or或,-not是not非

    # 属主不是user1也不是user2的普通文本文件
    $ find /tmp/test/ -not -user user1 -a -not -user user2 -a -type f
    
  12. -perm:按照文件的权限来查找,permission

    • MODE:精确匹配
    • -MODE:文件权限能够完全包含此MODE时才符合条件
    • /MODE:9位权限(rwxrwxrwx)中任何一位匹配就可以
    $ find /etc -perm 755 | head -2
    /etc
    /etc/xdg
    root@basil-2020:~# find /etc -perm 644 | head -2
    /etc/xdg/libfm/libfm.conf
    /etc/xdg/ui/ui_standards.rc
    
    $ find /etc -perm 644 -ls | head -2
    16777282    4 -rw-r--r--   1 root     root          465 Jan 11 10:17 /etc/fstab
    16777653    4 -rw-r--r--   1 root     root           51 Jan 15 19:53 /etc/resolv.conf
    
  13. 动作

    • 默认不写,是-print
    • -ls是长格式查看,类似ll
    • -delete是删除
    • -ok COMMAND {} \;找到了执行命令, 每次都需要用户确认,{}代表是源文件(引用),\;是结束符
    • -exec COMMAND {} \;找到了执行命令, 不需要用户确认,{}代表是源文件(引用),\;是结束符
    • 也可以和xargs连用
    $ find . -name "*.sh" -exec chmod o-x {} \;
    

2.1.2 练习

# 查找/var目录下属主为root并且属组为mail的所有文件;
$ find /var -user root -group mail
/var/spool/mail
/var/spool/mail/root

# 查找/usr目录下不属于root,bin,或user1的文件;
$ find /usr -not \( -user root -o -user bin -o -user user1 \)
/usr/share/polkit-1/rules.d

# 查找/etc目录下最近一周内内容修改过且不属于root及user1用户的文件;
find /etc -mtime -7 -not \ ( -user root -o -user student \)
find /etc -mtime -7 -not -user root -a -not -user student

# 查找当前系统上没有属主或属组且最近1天内曾被访问过的文件,并将其属主属组均修改为root;
find / \( -nouser -o -nogroup \) -a -atime -1 -exec chown root:root {} \; 

# 查找/etc目录下大于1M的文件,并将其文件名写入/tmp/etc.largefiles文件中;
find /etc -size +1M >> /tmp/etc.largefiles

# 查找/etc目录下所有用户都没有写权限的文件,显示出其详细信息;
find /etc -not -perm /222 -ls

2.2 which/whereis

查找命令或软件的绝对路径。

# which <command> 	# 查看所在命令/软件的位置
$ which ls
basil@basil-2020:~$ which ls
ls: aliased to ls --color=tty

# whereis <command>
$ whereis ls
basil@basil-2020:~$ whereis ls
ls: /usr/bin/ls /usr/share/man/man1/ls.1.gz

2.3 locate

好像不自带。配套updatedb强制刷新系统,更新会很慢,因为是整个系统级别

属于非实时查找的,模糊匹配,查找的结果可能包含目录,但是查找速度比较快。

# locate <command>/<filename>
$ locate ls
$ updatedb			# 刷新系统,不然新建文件不见得可以找到

3. 文件打包和压缩

常见压缩格式:gz、bz2、xz、zip。

3.1 打包

tar,是*nix系统中备份文件的可靠方法,几乎可以工作于任何环境中,它的使用权限是所有用户,建议针对目录来做。

打包, tar -cvf etc.tar /etc -c(reate)创建, -v(erbose)显示过程,-f(ilename)打包名。

3.2 压缩解压

  1. 只能压缩文件
    • gzip FILENAME:压缩,之后会删除源文件,生成FILENAME.gz。解压缩使用gunzip FILENAME.gz
      • gzip -d FILENAME.gz也是解压缩;
      • gzip -9 FILENAME是指定压缩比,可以指定1-9,默认是6
      • zcat FILENAME.gz是查看压缩文件中的内容,但是不会解压文本文件;
    • bzip2 FILENAME:压缩,比gzip压缩比更大,使用格式近似于gzip,选项也类似-d -9。不同的选项-k可以保留源文件。bunzip FILENAME.bz2也用于解压缩。
      • bzcat FILENAME.gz查看压缩文件的内容,不会解压文件。
    • xz FILENAME:压缩比比bzip2更大,也会删除源文件。-d -9 -k使用方法同bzip2。unxz或者xzdec也是解压缩。
  2. 可以压缩目录和文件
    • zip FILENAME.zip FILE1 FILE2...:压缩比不大,可以压缩目录。归档指把多个文件归档成一个,归档本身不意味着压缩。会默认保留源文件。
  3. 只归档不压缩
    • tar:只归档不压缩的工具,就是多个文件打成一个tar包。
      • -c:创建归档文件
      • -f FILE.tar:指定文件tar包名
      • -x:指定解包名
      • --xattrs:归档时,保留文件的扩展属性信息
      • -t:不解压不展开归档时查看归档了哪些文件

压缩

  • tar -czf etc.tar.gz /etc-z就代表gzip格式来压缩。
  • tar -cjf etc.tar.bz2 /etc-j是代表bzip2格式来压缩。压缩比例比gzip大。
  • tar -cJf etc.tar.xz /etc-J是代表xzip格式来压缩。压缩比例比bzip2大。

解压/解包,tar -xvf etc.tar-x是解包,-f指定要解压的文件名

  • tar -tf etc.tar-t指定-f的文件名,不解压,只是查看其中的文件
  • -C将解压出来的内容放到的目录,目录需要先存在
  • tar -zxvf etc.tar.gz-z指定解压方式是gzip,不指定linux也会自己判断

cpio也是一个归档工具。