跟老男孩学Linux运维:核心系统命令实战
上QQ阅读APP看书,第一时间看更新

2.6 ls:显示目录下的内容及相关属性信息

2.6.1 命令详解

【命令星级】 ★★★★★

【功能说明】

ls命令可以理解为英文单词list的缩写,其功能是列出目录的内容及其内容属性信息(list directory contents)。该命令有点类似于DOS系统下的dir命令,有趣的是,Linux下其实也有dir命令,但我们更习惯于使用ls。

【语法格式】

ls  [option]  [file]
ls  [选项]    [<文件或目录>]

特别说明:

1)ls命令以及后面的选项和文件,每个元素之间都至少要有一个空格。

2)命令后面的选项和目录文件可以省略,表示查看当前路径的文件信息。

【选项说明】

表2-7针对该命令的参数选项进行了说明。

表2-7 ls命令的参数选项及说明

2.6.2 使用范例

在开始范例讲解之前,需要先做一些准备,顺便整合一下前面使用的命令。

[root@oldboy ~]# mkdir /test  #<==在根“/”下创建一个目录test。
[root@oldboy ~]# cd /test/    #<==切到/test目录下。
[root@oldboy test]# touch file1.txt file2.txt file3.txt #<==批量创建若干文件。
[root@oldboy test]# mkdir dir1 dir2 dir3 #<==批量创建多个目录,每个目标目录名两端都                                          要有空格。
[root@oldboy test]# tree                  #<==显示前面创建的文件及目录结构。
.
├── dir1
├── dir2
├── dir3
├── file1.txt
├── file2.txt
└── file3.txt
3 directories, 3 files

1.基础范例

范例2-24:直接执行ls命令,不带任何参数。

[root@oldboy test]# ls  #<==不加参数的结果,显示所有文件和目录。
dir1  dir2  dir3  file1.txt  file2.txt  file3.txt

范例2-25:使用-a参数显示所有文件,特别是隐藏文件。

[root@oldboy test]# touch .file4.txt #<==再创建一个隐藏文件,在Linux系统中以“.”(点                                      号)开头的文件就是隐藏文件。
[root@oldboy test]# ls
dir1  dir2  dir3  file1.txt  file2.txt  file3.txt
[root@oldboy test]# ls -a
.  ..  dir1  dir2  dir3  file1.txt  file2.txt  file3.txt  .file4.txt
#<==说明:加了-a参数,就会把以“.”(点号)开头的内容显示出来了。这里显示的第一个点号,表示当前目录,即test目录本身,而两个点号则表示当前目录的上级目录,此处就代表根目录了。有关一个点、两个点的知识,在后面的ln命令中会有详细讲解。
[root@oldboy test]# ls -A #<==列出所有文件,包括隐藏文件,但不包括“.”与“..”这两个                              目录。
dir1  dir2  dir3  file1.txt  file2.txt  file3.txt  .file4.txt

范例2-26:使用-l参数显示详细信息。

[root@oldboy test]# ls -l  #<==此处的时间属性列默认显示的是文件的最后一次修改时间。
total 12
drwxr-xr-x 2 root root 4096 Oct 25 11:13 dir1
drwxr-xr-x 2 root root 4096 Oct 25 11:13 dir2
drwxr-xr-x 2 root root 4096 Oct 25 11:13 dir3
-rw-r--r-- 1 root root    0 Oct 25 11:13 file1.txt
-rw-r--r-- 1 root root    0 Oct 25 11:13 file2.txt
-rw-r--r-- 1 root root    0 Oct 25 11:13 file3.txt
#<==说明:这个-l参数是最常用的参数了,意思是用长格式列出目录下的文件类型、权限、连接数、属主(组)及创建修改时间的信息。这里每个列的属性含义都需要熟练掌握,后文会详细讨论这些属性信息。

可能有人已经注意到了,创建或修改时间的格式没有年份的信息,那么如何显示时间的全部信息呢?请看范例2-27。

范例2-27:显示完整时间属性的参数--time-style=long-iso。

[root@oldboy test]# ls -l --time-style=long-iso   #<==以long-iso方式显示时间,这个命令的结果是非常棒的。
total 12
drwxr-xr-x 2 root root 4096 2015-10-25 11:13 dir1
drwxr-xr-x 2 root root 4096 2015-10-25 11:13 dir2
drwxr-xr-x 2 root root 4096 2015-10-25 11:13 dir3
-rw-r--r-- 1 root root    0 2015-10-25 11:13 file1.txt
-rw-r--r-- 1 root root    0 2015-10-25 11:13 file2.txt
-rw-r--r-- 1 root root    0 2015-10-25 11:13 file3.txt
#<==提示:这样的时间格式看起来是不是总让人感到心情舒畅呢?关于--time-style的其他可选参数请大家自行测试。

对于上面的命令,说明如下:

1)--time-style可选的参数值有如下几个,如full-iso、long-iso、iso、locale。默认值是locale。

2)在生产场景中经常会遇到同一目录下的文件及目录时间的显示不一致的问题,所以需要用ls-l--time-style=long-iso来调整,如果觉得参数太多不好记,则可以设置一个别名管理,见后文的alias命令。

3)值得一提的是,执行ls-l等命令时,默认显示的是文件最后一次的修改时间(如果是新文件那么就是创建时间了)。

4)ls--full-time用于显示完整的时间,等同于ls-l--time-style=full-iso。

既然ls-l输出结果的时间属性列为修改时间,那么能否改成其他的时间呢?例如:显示最后一次文件访问时间。这当然也是可以的,具体请参见范例2-28。

范例2-28:执行ls命令,带显示内容的访问时间属性的参数。

[root@oldboy test]# stat file1.txt  #<==显示文件的属性及状态信息,stat命令会放在后                                     文讲解,暂时不用理会。
  File: 'file1.txt'
  Size: 0               Blocks: 0          IO Block: 4096   regular empty file
Device: 802h/2050d      Inode: 271005      Links: 1
Access: (0644/-rw-r--r--)  Uid: (    0/    root)   Gid: (    0/    root)
Access: 2015-10-25 11:13:38.875401372 +0800 #<==这里就是文件的访问时间,是我们现在
                                            需要关注的。
Modify: 2015-10-25 11:13:38.875401372 +0800
Change: 2015-10-25 11:13:38.875401372 +0800
[root@oldboy test]# date #<==查看当前系统时间。
Sun Oct 25 19:44:00 CST 2015
[root@oldboy test]# cat file1.txt   #<==查看文件内容即表示访问了文件,cat命令后面会讲,
                                     暂时不用理会。
[root@oldboy test]# stat file1.txt  #<==重新查看文件的访问时间。
  File: 'file1.txt'
  Size: 0               Blocks: 0          IO Block: 4096   regular empty file
Device: 802h/2050d      Inode: 271005      Links: 1
Access: (0644/-rw-r--r--)  Uid: (    0/    root)   Gid: (    0/    root)
Access: 2015-10-25 19:44:22.033071250 +0800 #<==可以发现file1.txt的访问时间已经
                                            发生了变化。
Modify: 2015-10-25 11:13:38.875401372 +0800
Change: 2015-10-25 11:13:38.875401372 +0800
[root@oldboy test]# ls -l --time-style=long-iso --time=atime #<==增加--time= atime参数,显示访问时间。
total 12
drwxr-xr-x 2 root root 4096 2015-10-25 11:13 dir1
drwxr-xr-x 2 root root 4096 2015-10-25 11:13 dir2
drwxr-xr-x 2 root root 4096 2015-10-25 11:13 dir3
-rw-r--r-- 1 root root    0 2015-10-25 19:44 file1.txt #<==文件的时间列确实发生了
                                                      变化,是前面的访问时间
                                                      无疑。
-rw-r--r-- 1 root root    0 2015-10-25 11:13 file2.txt
-rw-r--r-- 1 root root    0 2015-10-25 11:13 file3.txt
[root@oldboy test]# ls -l --time-style=long-iso
total 12
drwxr-xr-x 2 root root 4096 2015-10-25 11:13 dir1
drwxr-xr-x 2 root root 4096 2015-10-25 11:13 dir2
drwxr-xr-x 2 root root 4096 2015-10-25 11:13 dir3
-rw-r--r-- 1 root root    0 2015-10-25 11:13 file1.txt #<==这里是文件的默认修改时
                                                      间列。
-rw-r--r-- 1 root root    0 2015-10-25 11:13 file2.txt
-rw-r--r-- 1 root root    0 2015-10-25 11:13 file3.txt
#<==通过以上实践,可以得出结论了。--time=atime显示的确实是访问时间,而非默认的修改时间。

对于上面的命令,需要说明如下两点。

·与之相关命令还有ls-l--time-style=long-iso--time=ctime,用于显示文件改变的时间。

·有关文件时间列及mtime、atime、ctime的知识,前文在介绍touch命令时已经讲解过了。

范例2-29:执行ls命令,带-F参数(这一点与tree命令的-F很类似)。

[root@oldboy test]# ls -F
dir1/  dir2/  dir3/  file1.txt  file2.txt  file3.txt
#<==说明:加了-F,我们可以清晰地看到所有目录的结尾都被加上了斜线/。这样的功能对于工作有什么用呢?当然有用了,例如:我们要过滤出所有的目录来,那么只需要把带斜线的过滤出来就OK了。
[root@oldboy test]# ls -F|grep / #<==过滤目录,关于grep命令的具体用法请参见后面的grep
                                  grep章节。
dir1/
dir2/
dir3/
[root@oldboy test]# ls -F|grep -v /  #<==过滤普通文件。
file1.txt
file2.txt
file3.txt
#<==说明:ls的-F参数是在文件结尾加上文件类型指示符号(*、/、=、@、|,其中的一个)。

范例2-30:使用-d参数只显示目录本身的信息。

有时候我们想查看目录本身的信息,但是若使用“ls目录”命令,就会显示目录里面的内容。比如:

[root@oldboy test]# ls -l dir1  #<==这样根本无法查看dir1目录本身的信息,除非到上级目
                                  录下查看。
total 0

如果只是想显示目录本身的信息,那么这个时候-d就派上用场了。

[root@oldboy test]# ls -ld dir1 #<==加-d参数就可以如愿以偿了。
drwxr-xr-x 2 root root 4096 Oct 25 11:13 dir1

范例2-31:使用-R参数递归查看目录。

[root@oldboy test]# mkdir dir1/sub1/test -p  #<==递归创建目录的命令。
[root@oldboy test]# ls -R dir1               #<==类似但没有tree好用的方法。
dir1:
sub1
dir1/sub1:
test
dir1/sub1/test:

2.技巧性范例

范例2-32:ls命令别名的相关知识及设置ls别名。

可通过如下命令查看ls在系统中别名的默认设置,执行等号前面的内容就会调用后面的命令:

[root@oldboy test]# alias|grep ls  #<==关于alias命令的用法请参见alias章节。
alias l.='ls -d .* --color=tty'
alias ll='ls -l --color=tty'
alias ls='ls --color=tty'
#<==提示:什么是别名呢?别名很好理解,就是另外一个名字而已。

例如,若显示时间格式的参数太长,则可以做个别名:

[root@oldboy test]# alias lst='ls -l --time-style=long-iso' #<==配置命令别名。
[root@oldboy test]# alias |grep lst                  #<==检查命令别名是否生效。
alias lst='ls -l --time-style=long-iso'
[root@oldboy test]# lst                              #<==执行命令别名,检查效果。
total 12
drwxr-xr-x 2 root root 4096 2015-10-25 11:13 dir1
drwxr-xr-x 2 root root 4096 2015-10-25 11:13 dir2
drwxr-xr-x 2 root root 4096 2015-10-25 11:13 dir3
-rw-r--r-- 1 root root    0 2015-10-25 11:13 file1.txt
-rw-r--r-- 1 root root    0 2015-10-25 11:13 file2.txt
-rw-r--r-- 1 root root    0 2015-10-25 11:13 file3.txt
#<==注意:这里的别名是临时生效的,如果希望永久生效则需要放到环境变量的配置里才可以。

范例2-33:查找最近更新过的文件。

在工作中,我们经常需要查看一个有很多文件的目录,找出最近更新过但不知道具体文件名的文件,这时就可以用ls-lrt或ls-rt这个组合命令。

[root@oldboy test]# touch /etc/test.txt      #<==创建一个新文件,假设不知道名字,你如何快
                                        速找到它?
[root@oldboy test]# ls -lrt /etc/      #<==-t是按时间排序,-r是倒序,即按时间倒序排序。
...省略N多文件行...
-rw-r--r--  1 root root     301 May 22 10:17 mtab
drwxr-xr-x  9 root root    4096 May 22 10:22 sysconfig
-rw-r--r--  1 root root       0 May 22 20:55 test.txt
#<==不用翻屏回查,最后一屏的最后一行就是我们需要查找的文件。如果直接定位文件还可以用如下命令。
[root@oldboy test]# ls -lrt /etc|tail -1  #<==tail命令后面会讲。
-rw-r--r--  1 root root       0 May 22 20:55 test.txt

3.生产案例

范例2-34:生产场景数据库备份,获取数据库名列表。

#!/bin/bash
#  backup database and save one week data
#  oldboy   2007-02-02
destdir=/data/mysql_backup
mysqldumpbin=/usr/local/mysql/bin/mysqldump
ls -F /usr/local/mysql/data|egrep "/"|awk -F "/" '{print $1}' >/root/dbfilename.list
...省略部分...
#<==提示:在此数据库分表备份脚本中,用到了ls -F加egrep的组合命令来把数据库目录名过滤出来。

范例2-35:在生产场景下删除占用inode节点的垃圾。

===========================CentOS5.X默认安装sendmail邮件程序=====================
[root@oldboy ~]# cd /var/spool/clientmqueue/            #<==sendmail邮件临时目录。
[root@oldboy clientmqueue]# ls|xargs rm -f
[root@oldboy clientmqueue]# ll
total 0
===========================CentOS6.X默认安装postfix邮件程序===================
[root@mysql-1-174 ~]# cd /var/spool/postfix/maildrop/      #<==postfix邮件临时目录。
[root@mysql-1-174 maildrop]# ls
000C5279D6  11603270EE  2406C277DD  3595B26C2E  46BD326C17  57B4426FCF  699F727810  …………
[root@mysql-1-174 maildrop]# ls|xargs rm -f #<==如果文件特别多,那么直接rm -fr *
                                               是无法删除的。
[root@mysql-1-174 maildrop]# ls

在生产环境中,若是系统服务配置不当,例如设置了定时任务,则可能会导致/var/spool/clientmqueue/或/var/spool/postfix/maildrop/目录下碎文件过多,使得系统空间被垃圾充满,那么,此案例给出的是手工解决的办法。当然还可以通过定时任务执行本案例,这里的ls命令也可以用find命令来代替。

2.6.3 ls-F命令的扩展知识

从前面的范例可以看到,目录的结尾加上了斜线(/),若是其他类型的文件,就不是加斜线了,而是别的符号,具体如下:

[root@oldboy test]# ls -l /etc/init.d
lrwxrwxrwx. 1 root root 11 Feb  9  2015 /etc/init.d -> rc.d/init.d
[root@oldboy test]# ls -F /etc/init.d
/etc/init.d@  #<==链接文件结尾是@
[root@oldboy oldboy]# ls -F /bin/date
/bin/date*    #<==命令结尾是*

ls-F命令表示在每个文件名后附上一个字符以说明文件的类型:

man ls:
       -F, --classify
              append indicator (one of */=>@|) to entries

1)加上“*”代表可执行的普通文件:

[root@oldboy test]# ls -lF /etc/init.d/|egrep "ssh|syslog|crond"
#<==grep和egrep命令都可以过滤指定的字符串,具体用法请参见grep命令章节。
-rwxr-xr-x. 1 root root  2826 Nov 23  2013 crond*
-rwxr-xr-x. 1 root root  2011 Aug 15  2013 rsyslog*
-rwxr-xr-x. 1 root root  4621 Oct 15  2014 sshd*

2)加上“/”表示目录:

[root@oldboy test]#  ls -lF /etc|egrep "sysconfig|ssh"
drwxr-xr-x.  2 root root   4096 Oct 25 17:34 ssh/
drwxr-xr-x.  7 root root   4096 Aug 12 19:27 sysconfig/

3)加上“=”表示套接字(sockets):

[root@oldboy test]# find / -type s -exec ls -lF {} \;
#<==这是查找不同类型文件的find命令,后文会讲。
srwxr-xr-x 1 oldboy oldboy 0 May 22 11:32 /tmp/ssh-hOnVuA2802/agent.2802=
srwxr-xr-x 1 oldboy oldboy 0 May 22 10:22 /tmp/ssh-oaYxtw2626/agent.2626=
srwxr-xr-x 1 oldboy oldboy 0 May 22 11:04 /tmp/ssh-zKAcZl2738/agent.2738=
srw-rw-rw- 1 root root 0 May 22 10:17 /dev/log=

4)加上“|”表示FIFOs:

[root@oldboy test]# find / -type p -exec ls -lF {} \;
prw------- 1 root root 0 May 22 10:16 /dev/initctl|

5)加上“@”表示符号链接:

[root@oldboy test]# ls -lF /bin/sh
lrwxrwxrwx 1 root root 4 Dec 19 03:28 /bin/sh -> bash*

其实还有个类似的选项“-p”,它的功能比较简单,只是在目录后面加上“/”。大家可以自行试验。

2.6.4 ls命令输出内容的属性解读

在使用ls命令之后,通常会有类似如下的输出内容:

[root@oldboy test]# ls -lhi  #<==-l参数前面已经详细讲解过了,-h参数的作用是将文件的大小
                              以人类可读的方式进行显示,像下面的“4.0K”你很容易就知
                              道文件的大小,-i参数的作用是显示文件的inode值。
total 12K
97063 drwxr-xr-x 3 root root 4.0K May 22 20:48 dir1
97064 drwxr-xr-x 2 root root 4.0K May 22 11:51 dir2
97065 drwxr-xr-x 2 root root 4.0K May 22 11:51 dir3
97060 -rw-r--r-- 1 root root    0 May 22 11:51 file1.txt
97061 -rw-r--r-- 1 root root    0 May 22 11:51 file2.txt
97062 -rw-r--r-- 1 root root    0 May 22 11:51 file3.txt

上述命令结果中各列的含义具体如下。

第一列:inode索引节点编号。

第二列:文件类型及权限(第一个字符为类型,后9个字符为文件权限符号)。

第三列:硬链接个数(详细请参看ln命令的讲解)。

第四列:文件或目录所属的用户(属主)。

第五列:文件或目录所属的组。

第六列:文件或目录的大小。

第七、八、九列:文件或目录的修改时间。

第十列:实际的文件名或目录名。

详细解释见图2-2。

图2-2 ls命令输出内容的属性解读

ls输出的文件属性举例说明

下面以oldboy文件为例说明输出文件的属性细节(见表2-8),具体列的内容请参考图2-2。

1736707 -rw-r--r-- 1  root root   35  Oct 28 11:29 oldboy

表2-8 ls输出的文件属性细节说明