本文是学习Linux命令 (Learn linux command)系列文章的第三篇,在这里会介绍一些让大家平时都会经常用到的命令。注意,命令出现的顺序与重要程度无关。

1. ls - list directory contents

ls命令是用得比较多的一个命令,它用于列出某个目录下面的文件或者子目录及它们的属性(大小、创建时间、所属用户等信息)。

ls命令的参数比较多,这里只介绍一些实用的。

a. 通过-a选项列出目录下面的隐藏文件(即以.号开头的文件),例如:

# ls -a ~
.  ..  .bash_history  .bash_logout  .bash_profile  .bashrc  .cshrc .tcshrc  .viminfo

其中.和..表示当前目录与上一级目录,如果不想显示可以使用-A选项。

# ls -A ~
.bash_history  .bash_logout  .bash_profile  .bashrc .cshrc .tcshrc  .viminfo


b. 通过-l选项列出文件的详细信息,例如:

# ls -l /boot
total 19256
-rw-r--r--. 1 root root   101820 Jun 22  2012 config-2.6.32-279.el6.x86_64
drwxr-xr-x. 3 root root     4096 Dec 17 09:08 efi
drwxr-xr-x. 2 root root     4096 Dec 17 09:09 grub
-rw-r--r--. 1 root root 13057907 Dec 17 09:09 initramfs-2.6.32-279.el6.x86_64.img
-rw-r--r--. 1 root root   179157 Jun 22  2012 symvers-2.6.32-279.el6.x86_64.gz
-rw-r--r--. 1 root root  2341856 Jun 22  2012 System.map-2.6.32-279.el6.x86_64
-rwxr-xr-x. 1 root root  3986608 Jun 22  2012 vmlinuz-2.6.32-279.el6.x86_64

上面结果中的每一列的说明可以参考info ls:

print the file type, file mode bits, number of hard links, owner name, group name, size, and
timestamp (*note Formatting file timestamps::), normally the modification time.

参考手册我们一一来说明各个列分别对应的是:

  • 第一列表示文件的类型,其中'-'表示普通文件,'d'表示目录,'b'表示块设备文件,'c'表示字符设备文件,'l'表示符号链接,'p'表示管道文件, 's'表示socket文件等等;
  • 第二列是文件的权限位;
  • 第三列是硬链接的个数;
  • 第四、五列分别是文件所属的用户和用户组;
  • 第六列是指文件大小;
  • 第七列是文件的修改时间;
  • 第八列是文件的名称;

如果加上-i选项还可以列出文件的inode号,inode号将会显示在第一列。

c. 指定-d选项仅列出目录,而不是目录的内容。

有时候我们要列出一个目录的属性,但是不是列出目录的内容,如果我们使用ls -l /etc/会列出/etc/目录下的所有内容,这个时候就需要使用-d选项限制:

# ls -ld /etc
drwxr-xr-x. 59 root root 4096 Mar  4 16:40 /etc

d. 指定-h列出可读性高的结果,将大小转换成如1k, 200M, 3G等形式,例如:

# ls -lh /boot/
total 19M
-rw-r--r--. 1 root root 100K Jun 22  2012 config-2.6.32-279.el6.x86_64
drwxr-xr-x. 3 root root 4.0K Dec 17 09:08 efi
drwxr-xr-x. 2 root root 4.0K Dec 17 09:09 grub
-rw-r--r--. 1 root root  13M Dec 17 09:09 initramfs-2.6.32-279.el6.x86_64.img
-rw-r--r--. 1 root root 175K Jun 22  2012 symvers-2.6.32-279.el6.x86_64.gz
-rw-r--r--. 1 root root 2.3M Jun 22  2012 System.map-2.6.32-279.el6.x86_64
-rwxr-xr-x. 1 root root 3.9M Jun 22  2012 vmlinuz-2.6.32-279.el6.x86_64

--si选项类似-h,只不过--si假设1kb=1000b,而不是1024。

e. 使用--sort选项排序列出的文件,例如:

默认情况下是按照文件名排序,我们可以换成其它排序方式,例如按照时间排序:

# ls -l --sort=time /boot/
total 19256
drwxr-xr-x. 2 root root     4096 Dec 17 09:09 grub
-rw-r--r--. 1 root root 13057907 Dec 17 09:09 initramfs-2.6.32-279.el6.x86_64.img
drwxr-xr-x. 3 root root     4096 Dec 17 09:08 efi
-rw-r--r--. 1 root root   179157 Jun 22  2012 symvers-2.6.32-279.el6.x86_64.gz
-rw-r--r--. 1 root root   101820 Jun 22  2012 config-2.6.32-279.el6.x86_64
-rw-r--r--. 1 root root  2341856 Jun 22  2012 System.map-2.6.32-279.el6.x86_64
-rwxr-xr-x. 1 root root  3986608 Jun 22  2012 vmlinuz-2.6.32-279.el6.x86_64

--sort选项的值可以为none(按照inode号排序),size(文件大小排序),time(修改时间排序)等等。其中--sort=time相当于-t。

通过-r选项可以逆序排序,所以我们经常看到这样用:ls -ltr,表明按照修改时间逆序排序文件。

f. 使用-1(数字1)选项列出文件,一行一个文件,这个大多数用于脚本中。

2. touch - change file timestamps

touch命令可以用于创建空文件,这是我们平时使用最多的一点,而且它还可以用来更改文件的修改时间(mtime:文件内容最近修改的时间)和访问时间(atime:文件内容最近打开读的时间),同时将文件的改变时间(ctime:文件属性最近改变的时间)更新为当前时间。文件内容的修改也会更新ctime的时间。

例如当前目录有一个文件1.txt,当前它的atime/ctime/mtime如下所示:

# stat 1.txt 
  File: `1.txt'
  Size: 4         	Blocks: 8          IO Block: 4096   regular file
Device: ca01h/51713d	Inode: 270217      Links: 1
Access: (0755/-rwxr-xr-x)  Uid: (    0/    root)   Gid: (    0/    root)
Access: 2013-03-06 12:21:50.526594045 +0800
Modify: 2013-03-06 12:21:38.098237950 +0800
Change: 2013-03-06 12:21:58.866833152 +0800

现在我们执行touch 1.txt命令,它默认会更新所有的时间为当前时间:

# touch 1.txt
# stat 1.txt 
  File: `1.txt'
  Size: 4         	Blocks: 8          IO Block: 4096   regular file
Device: ca01h/51713d	Inode: 270217      Links: 1
Access: (0755/-rwxr-xr-x)  Uid: (    0/    root)   Gid: (    0/    root)
Access: 2013-03-06 12:23:20.909178823 +0800
Modify: 2013-03-06 12:23:20.909178823 +0800
Change: 2013-03-06 12:23:20.909178823 +0800

我们可以通过添加-m或者-a选项仅修改mtime或者atime(记住ctime是一定会变化的):

# touch -m 1.txt
# stat 1.txt
  File: `1.txt'
  Size: 4         	Blocks: 8          IO Block: 4096   regular file
Device: ca01h/51713d	Inode: 270217      Links: 1
Access: (0755/-rwxr-xr-x)  Uid: (    0/    root)   Gid: (    0/    root)
Access: 2013-03-06 12:23:20.909178823 +0800
Modify: 2013-03-06 12:24:40.891474834 +0800
Change: 2013-03-06 12:24:40.891474834 +0800

那如果想要设置成其它时间,可以通过-d或者-t参数指定,其中-d指定的格式比较智能,但是也不容易指定。比较推荐使用-t选项,它的值格式为[[CC]YY]MMDDhhmm[.ss],例如197001010000.00:

# touch -t 197001010000.00 -a 1.txt 
# stat 1.txt 
  File: `1.txt'
  Size: 4         	Blocks: 8          IO Block: 4096   regular file
Device: ca01h/51713d	Inode: 270217      Links: 1
Access: (0755/-rwxr-xr-x)  Uid: (    0/    root)   Gid: (    0/    root)
Access: 1970-01-01 00:00:00.000000000 +0800
Modify: 2013-03-05 11:00:00.000000000 +0800
Change: 2013-03-06 12:37:52.142045891 +0800
 Birth: -

参考资料:

  • http://www.linfo.org/touch.html
  • http://linux.about.com/library/cmd/blcmdl_touch.htm

3. du - estimate file space usage

du命令可以用于统计文件或者目录的大小,大多数情况下,这个命令可以用于监控某个目录的大小是否超过某个警界值。

例如:

$ date > 1.txt
$ du 1.txt 
4	1.txt

上面的结果表示1.txt这个文件有4KB,如果我们用ls -l命令查看结果却不一样:

$ ls -l 1.txt 
-rw-r--r-- 1 kodango kodango 29 Mar  9 12:52 1.txt

可见,实际的大小只有29byte,这也实际的大小是一致的。那为什么du和ls命令的结果有这样的区别呢,原因是ls命令默认显示的是文件的实际大小,而du命令是显示文件在物理硬盘上占用的大小,因为文件分配的最小单位是block,可以通过tune2fs命令查看文件系统的block size:

$ sudo tune2fs -l /dev/sda1 | grep 'Block size'
Block size:               4096

默认刚好是4K,所以du的命令结果就可以解释了。du命令也提供--apparent-size来显示文件的实际大小:

du --apparent-size -h 1.txt 
29	1.txt

这里的-h选项与ls的-h一样,将大小转换成如1k, 200M, 3G等形式,这样便于阅读,-h的进制是1024,如果要使用1000作为进制,可以使用--si选项,很多系统上都标明-h选项已经过时。

不指定参数的情况下du会计算当前目录下的子目录的大小,通过-a选项可以计算包括文件在内的所有大小,例如:

[kodango@devops temp]$ du -ah
4.0K	./sub/3.txt
8.0K	./sub
4.0K	./1.txt
8.0K	./2.txt
24K	.

4. df - report file system disk space usage

df命令用来显示文件系统的空间使用情况,因为针对的是文件系统,我们可以利用该命令很清晰地看出当前系统分区挂载的情况。一般情况下,我会通过-hT参数来显示:

$ df -hT
Filesystem    Type    Size  Used Avail Use% Mounted on
/dev/sda3     ext3    142G  133G  2.6G  99% /
/dev/sda1     ext3    487M  116M  346M  25% /boot
tmpfs        tmpfs     12G   52K   12G   1% /dev/shm

其中,-h将大小转换成易读的单位,例如M, G等,-T则是同时显示文件系统类型。

5. split - split a file into pieces

将一个大文件分割成多个小文件,这应该是一个比较常见的需求。有了split命令,分割文件的操作就很简单了,你根本不需要花心思再找工具甚至写代码来完成这个任务。

split命令将文件分割成PREFIXaa, PREFIXab, ...等多个小文件,默认情况下PREFIX为x,当然你也可以自己指定。这个命令的用法比较简单,下面是几个例子。

1) 以每个文件500行分割

$ split -l 500 messages
$ wc -l x*
   500 xaa
   500 xab
   500 xac
   242 xad
  1742 total

2) 以每个文件50K分割

$ split -b 50k messages
$ wc -c x*
 51200 xaa
 51200 xab
 44612 xac
147012 total

3) 指定前缀及数字后缀分割

$ split -b 50k -d messages msg
wc -c msg*
 51200 msg00
 51200 msg01
 44612 msg02
147012 total

6. md5sum - compute and check MD5 message digest

md5sum用于计算和检验文件的md5值,通过md5值我们可以唯一确定某个文件,从而验证文件的合法性,避免文件损坏。

md5sum有两种读入模式:binary和text,但是在Linux上这两者基本上没有什么区别,只不过输出时影响文件的标志位。如果是binary模式,在输出结果中文件名前面显示*;如果是text模式,则在输出结果中文件名前面显示空格,例如:

$ md5sum -b /bin/bash
e764fe17b0b5043e83838352e958f77d */bin/bash
$ md5sum /bin/bash
e764fe17b0b5043e83838352e958f77d  /bin/bash

注意第二个结果中,中间有两个空格,前面一个是用于分隔md5值与文件名,后一个空格是标志模式。

md5sum的另外一个作用是检验文件是否准确,在一些iso或者大型文件下载站,往往会给出文件对应的md5sums.txt,例如:

$ cat md5sums.txt 
63bb5b8b78b02cdc75fc23222b09c46a  messages
$ md5sum -c md5sums.txt 
messages: OK

这个时候,可以通过-c参数来检验文件,md5sums.txt的格式与之前用md5sum命令计算文件的md5值的输出格式是一样的。所以千万不要画龙点睛,把中间的两个空格写成一个空格哦。

7. uniq - report or omit repeated lines

uniq命令顾名思义就是用来处理重复行的,如果仅仅是删除重复行,我们在上一节中介绍的sort命令出可以完成这个任务(sort -u)。但是,uniq是专门用于处理重复行的,它的功能更加丰富点。

uniq处理的文件必须是已经排好序的(可以使用sort排序文件)。

我们用以下一个排好序的简单文件来解释uniq的用法:

$ cat ip.list
10.0.0.1
10.0.0.2
10.0.0.2
10.0.0.3

1)删除重复行

$ uniq ip.list 
10.0.0.1
10.0.0.2
10.0.0.3	

2) 统计相同行出现的次数

$ uniq -c ip.list
      1 10.0.0.1
      2 10.0.0.2
      1 10.0.0.3

3) 仅显示重复的行

$ uniq -d ip.list 
10.0.0.2

4) 仅显示不重复的行

$ uniq -u ip.list 
10.0.0.1
10.0.0.3

8. tr - translate or delete characters

tr是translate翻译的意思,它可以将一个集合内的字符(SET1)转换成另外一个集合内的字符(SET2)。当然,除这个最基本的功能外,它还有诸如删除、压缩等功能。

一个最常用的tr用法是将小写字母转换成大写字母:

$ echo "hello, world" | tr a-z A-Z
HELLO, WORLD

这里SET1是a-z,SET2是A-Z。a-z是tr支持的特殊序列,表示从a到z的所有小写字母,了解正则的同学可能会比较容易理解,因为同[a-z]的功能是一样的。

tr支持很多种序列的表示,具体可以看man的手册,这里再例举两个。

1) [CHAR*]与[CHAR*REPEAT]

这两种表示法只能用于SET2,前者是说SET2的字符全是CHAR,将SET1中的字符全部替换成CHAR;后者的意思是说CHAR字符重复REPEAT次,SET1中的前REPEAT个字符替换成CHAR。

举两个例子来说明:

$ echo '123456789' | tr 1-5 '[x*]'  # 1-5全部替换成x
xxxxx6789
$ echo '123456789' | tr 1-5 '[x*3]yz'  # 1-3替换成x,4-5替换成y-z
xxxyz6789

2) \NNN

\NNN是用1-3位的八进制数来表示字符,例如\101表示大写字母A:

$ echo '123456789' | tr 1-3 '\101-\103'
ABC456789

tr命令支持的参数不多,就以下几个,每个参数对应不同的操作:

$ tr --help
Usage: tr [OPTION]... SET1 [SET2]
Translate, squeeze, and/or delete characters from standard input,
writing to standard output.

  -c, -C, --complement    first complement SET1
  -d, --delete            delete characters in SET1, do not translate
  -s, --squeeze-repeats   replace each input sequence of a repeated character
                            that is listed in SET1 with a single occurrence
                            of that character
  -t, --truncate-set1     first truncate SET1 to length of SET2

其中:

  • -c:对SET1中的内容求补集,例如-c 1+-表示除1+-外的所有字符;
  • -d:删除出现在SET1中的字符,而不是翻译转换;
  • -s:将连续的并且出现在SET1中的字符压缩为一个;
  • -t:将SET1集合的长度裁成与SET2集合的长度相同,即SET1中末尾多余的字符会被忽略;

下面拿几个例子来解释以上的参数:

1) -c SET1

将除1-3和回车之外的所有字符替换成4(SET2仅能为单个字符?):

$ echo '123456789' | tr -c '1-3\n' 4
123444444

2) -d SET1

将1-3三个字符从字符串中删除:

$ echo '123456789' | tr -d '1-3'
456789

-d如果与-c参数一起使用,意思是指删除SET1出现的字符以外的其它字符:

$ echo '123456789' | tr -dc '1-3\n'
123

3) -s SET1

如果SET1中的字符,在字符串中连续现出,则压缩成1个:

$ echo '11233' | tr -s 1
1233

-s选项可以用于-d或者翻译转换的场景,但是在这两个情况下-s只压缩出现在SET2中的字符,例如

$ echo '11233' | tr -s 1-3 2-4  # 等价于 tr 1-3 2-4 && tr -s 2-4
234

4) -t SET1 SET2

这里的t是truncate的意思,如果SET1的长度比SET2大,则忽略SET1中多余的字符,例如:

$ echo '12345' | tr -t 1-5 2-4
23445

在这里仅替换了1、2、3三个字符,4-5则被忽略了。

9. mv - move (rename) files

mv是平时使用得比较多的一个命令,它用于移动文件或者目录,也可以说是对文件或者目录做重命名。但是一个简单的命令也有一些我们平时没有留意的地方。

1)如果目标文件或者目录存在怎么办,能不能先备份它?

$ touch source dst
$ mv -b source dst
$ ls dst* -1
dst
dst~

-b选项就是backup的意思,如果目标存在,则先备份。

2)如果仅仅要移动更新过的文件,能不能做到?

mv命令有一个-u选项,它仅仅当源文件比目标文件更新,或者目标文件不存在是才移动,例如

$ date > source
$ cp source source.bak
$ ls -lh source source.bak 
-rw-r--r-- 1 admin admin 29 May  2 14:50 source
-rw-r--r-- 1 admin admin 29 May  2 14:50 source.bak
$ mv -u source source.bak 
$ ls -lh source source.bak 
-rw-r--r-- 1 admin admin 29 May  2 14:50 source
-rw-r--r-- 1 admin admin 29 May  2 14:50 source.bak
$ date > source
$ mv -u source source.bak 
$ ls -lh source source.bak 
ls: source: No such file or directory
-rw-r--r-- 1 admin admin 29 May  2 14:51 source.bak