练习 8:更多的重定向和过滤:headtailawkgrepsed

    现在你试过了 Linux,我会介绍一下 Unix 的方式。注意看。

    这就是 Unix 的哲学:写一些程序,只做一件事,并且把它做好。编写程序,使其一起工作。编写程序来处理文本流,因为这是一个通用接口。

    这里发生的事情真的很简单。几乎每个 Linux 程序在启动时打开这三个文件:

    stdin - 标准输入。这是程序读取东西的地方。
    stdout - 标准输出。这是程序写出东西的地方。
    stderr - 标准错误。这是程序报错的地方。

    这就是它的读取方式:

    还有另一种方式来描绘发生的事情,如果你喜欢 South Park 风格的幽默,但要小心:看到的是不会是不可见的!。

    1. ls -al | tr -s ' ' | cut -d ' ' -f 8,9

    这是所发生事情的概述:

    更详细地说,这是每一步发生的事情:

    第一步:ls -al,我们获取了目录列表,每一列都叫做字段。

    1. user1@vm1:~$ ls -al
    2. total 52
    3. drwxr-xr-x 2 user1 user1 4096 Jun 18 14:16 .
    4. drwxr-xr-x 3 root root 4096 Jun 6 21:49 ..
    5. -rw------- 1 user1 user1 4865 Jun 15 19:34 .bash_history
    6. -rw-r--r-- 1 user1 user1 220 Jun 6 21:48 .bash_logout
    7. -rw-r--r-- 1 user1 user1 3184 Jun 14 12:24 .bashrc
    8. -rw-r--r-- 1 user1 user1 64 Jun 18 14:16 hello.txt
    9. -rw------- 1 user1 user1 89 Jun 18 16:26 .lesshst
    10. -rw-r--r-- 1 user1 user1 634 Jun 15 20:03 ls.out
    11. -rw-r--r-- 1 user1 user1 697 Jun 7 12:25 .profile
    12. -rw-r--r-- 1 user1 user1 741 Jun 7 12:19 .profile.bak
    13. -rw-r--r-- 1 user1 user1 741 Jun 7 13:12 .profile.bak1
    14. -rw------- 1 user1 user1 666 Jun 18 14:16 .viminfo

    第二步:ls -al | tr -s ' ',我们在两个字段之间只保留,因为cut不能将多个空格理解为一种方式,来分离多个字段。

    第三步:我们只保留字段 8 和 9,它们是我们想要的。

    1. user1@vm1:~$ ls -al | tr -s ' ' | cut -d ' ' -f 8,9
    2. 14:16 .
    3. 21:49 ..
    4. 19:34 .bash_history
    5. 21:48 .bash_logout
    6. 12:24 .bashrc
    7. 14:16 hello.txt
    8. 16:26 .lesshst
    9. 20:03 ls.out
    10. 12:25 .profile
    11. 12:19 .profile.bak
    12. 13:12 .profile.bak1
    13. 14:16 .viminfo
    1. user1@vm1:~$ ls -al | head -n 5
    2. total 52
    3. drwxr-xr-x 2 user1 user1 4096 Jun 18 14:16 .
    4. drwxr-xr-x 3 root root 4096 Jun 6 21:49 ..
    5. -rw------- 1 user1 user1 4865 Jun 15 19:34 .bash_history
    6. user1@vm1:~$ ls -al | tail -n 5
    7. -rw-r--r-- 1 user1 user1 636 Jun 18 17:52 ls.out
    8. -rw-r--r-- 1 user1 user1 697 Jun 7 12:25 .profile
    9. -rw-r--r-- 1 user1 user1 741 Jun 7 12:19 .profile.bak
    10. -rw-r--r-- 1 user1 user1 741 Jun 7 13:12 .profile.bak1
    11. user1@vm1:~$ ls -al | awk '{print $8, $9}'
    12. 14:16 .
    13. 21:49 ..
    14. 19:34 .bash_history
    15. 21:48 .bash_logout
    16. 12:24 .bashrc
    17. 14:16 hello.txt
    18. 16:26 .lesshst
    19. 17:52 ls.out
    20. 12:25 .profile
    21. 12:19 .profile.bak
    22. 13:12 .profile.bak1
    23. 14:16 .viminfo
    24. user1@vm1:~$ ls -al | awk '{print $9, $8}'
    25. . 14:16
    26. .. 21:49
    27. .bash_history 19:34
    28. .bash_logout 21:48
    29. .bashrc 12:24
    30. hello.txt 14:16
    31. .lesshst 16:26
    32. ls.out 17:52
    33. .profile 12:25
    34. .profile.bak 12:19
    35. .profile.bak1 13:12
    36. .viminfo 14:16
    37. user1@vm1:~$ ls -al | awk '{printf "%-20.20s %s\n",$9, $8}'
    38. . 14:16
    39. .. 21:49
    40. .bash_history 19:34
    41. .bash_logout 21:48
    42. .bashrc 12:24
    43. hello.txt 14:16
    44. .lesshst 16:26
    45. ls.out 17:52
    46. .profile 12:25
    47. .profile.bak 12:19
    48. .profile.bak1 13:12
    49. .viminfo 14:16
    50. user1@vm1:~$ ls -al | grep bash
    51. -rw-r--r-- 1 user1 user1 220 Jun 6 21:48 .bash_logout
    52. -rw-r--r-- 1 user1 user1 3184 Jun 14 12:24 .bashrc
    53. user1@vm1:~$ ls -al > ls.out
    54. user1@vm1:~$ cat ls.out
    55. total 48
    56. drwxr-xr-x 2 user1 user1 4096 Jun 18 14:16 .
    57. drwxr-xr-x 3 root root 4096 Jun 6 21:49 ..
    58. -rw------- 1 user1 user1 4865 Jun 15 19:34 .bash_history
    59. -rw-r--r-- 1 user1 user1 220 Jun 6 21:48 .bash_logout
    60. -rw-r--r-- 1 user1 user1 3184 Jun 14 12:24 .bashrc
    61. -rw-r--r-- 1 user1 user1 64 Jun 18 14:16 hello.txt
    62. -rw------- 1 user1 user1 89 Jun 18 16:26 .lesshst
    63. -rw-r--r-- 1 user1 user1 0 Jun 18 17:53 ls.out
    64. -rw-r--r-- 1 user1 user1 697 Jun 7 12:25 .profile
    65. -rw-r--r-- 1 user1 user1 741 Jun 7 12:19 .profile.bak
    66. -rw-r--r-- 1 user1 user1 741 Jun 7 13:12 .profile.bak1
    67. -rw------- 1 user1 user1 666 Jun 18 14:16 .viminfo
    68. user1@vm1:~$ cat ls.out | sed 's/bash/I replace this!!!/g'
    69. total 48
    70. drwxr-xr-x 2 user1 user1 4096 Jun 18 14:16 .
    71. drwxr-xr-x 3 root root 4096 Jun 6 21:49 ..
    72. -rw------- 1 user1 user1 4865 Jun 15 19:34 .I replace this!!!_history
    73. -rw-r--r-- 1 user1 user1 220 Jun 6 21:48 .I replace this!!!_logout
    74. -rw-r--r-- 1 user1 user1 3184 Jun 14 12:24 .I replace this!!!rc
    75. -rw-r--r-- 1 user1 user1 64 Jun 18 14:16 hello.txt
    76. -rw------- 1 user1 user1 89 Jun 18 16:26 .lesshst
    77. -rw-r--r-- 1 user1 user1 0 Jun 18 17:53 ls.out
    78. -rw-r--r-- 1 user1 user1 697 Jun 7 12:25 .profile
    79. -rw-r--r-- 1 user1 user1 741 Jun 7 12:19 .profile.bak
    80. -rw-r--r-- 1 user1 user1 741 Jun 7 13:12 .profile.bak1
    81. -rw------- 1 user1 user1 666 Jun 18 14:16 .viminfo
    • 只打印目录列表中的前 5 个条目。
    • 只打印目录列表中的后 5 个条目。
    • 只打印修改时间和文件名。注意我如何使用awk,这比cut更聪明。这里的区别就是,cut只能将单个符号(我们这里是空格)理解为一种方式,来分离字段(字段分隔符),awk将任意数量的空格和 TAB 看做文件分隔符,所以没有必要使用tr来消除不必要的空格。
    • 按此顺序打印文件名和修改时间。这又是cat不能做的事情。
    • 工整地打印文件名和修改时间。注意现在输出如何变得更清晰。
    • 仅打印目录列表中包含bash的行。
    • 将目录列表的输出写入文件ls.out
    • 打印出ls.outcat是最简单的可用程序,允许你打印出一个文件,没有更多了。尽管如此简单,但在构建复杂管道时非常有用。
    • 打印出ls.out,将所有的bash条目替换为I replace this!!!sed是一个强大的流编辑器,它非常非常非常有用。
    • 打开headtailawkgrepsed的手册页。不要害怕,只要记住手册页面总是在那里。有了一些实践,你将能够实际了解他们。
    • 查找选项,能够打印它找到的那行之前,或之后的一行。
    • 使用 Google 搜索awk printf命令,尝试了解它如何工作。
    • 阅读 The Useless Use of Cat Award。尝试那里的一些例子。