• 练习 7:Bash:重定向,stdinstdoutstderr<>>>|teepv
    • 这样做
    • 你应该看到什么
    • 解释
    • 附加题

    练习 7:Bash:重定向,stdinstdoutstderr<>>>|teepv

    原文:Exercise 7. Bash: redirection, stdin, stdout, stderr, <, >, >>, |, tee, pv

    译者:飞龙

    协议:CC BY-NC-SA 4.0

    自豪地采用谷歌翻译

    在 Linux 中,一切都只是文件。这意味着,对于控制台程序:

    • 键盘表示为一个文件,Bash 从中读取你的输入。
    • 显示器表示为一个文件,Bash向输出写入它。

    让我们假设,你有一个程序可以计算文件中的行。你可以通过键入wc -l来调用它。现在尝试一下 没有发生什么事吧?它只是卡在那里。错了,它正在等待你的输入。这是它的工作原理:

    1. line_counter = 0
    2. while end of file is not reached
    3. read a line
    4. add 1 to line_counter
    5. print line_counter

    所以wc目前从/dev/tty读取行,这在当前上下文中是你的键盘。每次你按下回车,wc都会获取一行。任意键入几行,然后按CTRL + D,这将为wc产生EOF字符,使其明白达到文件末尾。现在它会告诉你你输入了多少行。

    但是如果你想计算现有文件中的行呢?那么,这就需要重定向 了!为了在其输入上提供现有文件,请键入以下内容:wc -l < .bash_history。你看,它有作用!真的是那么简单!重定向 是一种机制,允许你告诉程序,将其来自键入输入和/或到显示器的输出,重定向到另一个文件。为此,你可以使用这些特殊命令,然后启动程序:

    • < - 用文件替换标准输入(例如键盘)。
    • > - 用文件替换标准输出(例如显示器)。警告!此命令将覆盖 你的指定文件的内容,因此请小心。
    • >> - 与上面相同,但不是覆盖 文件,而是写入到它的末尾,保存在该文件中已存在的信息。小心不要混淆两者。
    • | - 从一个程序获取输出,并将其连接到另一个程序。这将在下一个练习中详细阐述。

    现在,你将学习如何将程序的输入和输出重定向到文件或其他程序。

    这样做

    1. 1: sudo aptitude install pv
    2. 2: read foo < /dev/tty
    3. 3: Hello World!
    4. 4: echo $foo > foo.out
    5. 5: cat foo.out
    6. 6: echo $foo >> foo.out
    7. 7: cat foo.out
    8. 8: echo > foo.out
    9. 9: cat foo.out
    10. 10: ls -al | grep foo
    11. 11: ls -al | tee ls.out
    12. 12: dd if=/dev/zero of=~/test.img bs=1M count=10
    13. 13: pv ~/test.img | dd if=/dev/stdin of=/dev/null bs=1
    14. 14: rm -v foo.out
    15. 15: rm -v test.img

    你应该看到什么

    1. user1@vm1:~$ sudo aptitude install pv
    2. The following NEW packages will be installed:
    3. pv
    4. 0 packages upgraded, 1 newly installed, 0 to remove and 0 not upgraded.
    5. Need to get 0 B/28.9 kB of archives. After unpacking 143 kB will be used.
    6. Selecting previously deselected package pv.
    7. (Reading database ... 39657 files and directories currently installed.)
    8. Unpacking pv (from .../archives/pv_1.1.4-1_amd64.deb) ...
    9. Processing triggers for man-db ...
    10. Setting up pv (1.1.4-1) ...
    11. user1@vm1:~$ read foo < /dev/tty
    12. Hello World!
    13. user1@vm1:~$ echo $foo > foo.out
    14. user1@vm1:~$ cat foo.out
    15. Hello World!
    16. user1@vm1:~$ echo $foo >> foo.out
    17. user1@vm1:~$ cat foo.out
    18. Hello World!
    19. Hello World!
    20. user1@vm1:~$ echo > foo.out
    21. user1@vm1:~$ cat foo.out
    22. user1@vm1:~$ ls -al | grep foo
    23. -rw-r--r-- 1 user1 user1 1 Jun 15 20:03 foo.out
    24. user1@vm1:~$ ls -al | tee ls.out
    25. total 44
    26. drwxr-xr-x 2 user1 user1 4096 Jun 15 20:01 .
    27. drwxr-xr-x 3 root root 4096 Jun 6 21:49 ..
    28. -rw------- 1 user1 user1 4865 Jun 15 19:34 .bash_history
    29. -rw-r--r-- 1 user1 user1 220 Jun 6 21:48 .bash_logout
    30. -rw-r--r-- 1 user1 user1 3184 Jun 14 12:24 .bashrc
    31. -rw-r--r-- 1 user1 user1 1 Jun 15 20:03 foo.out
    32. -rw------- 1 user1 user1 50 Jun 15 18:41 .lesshst
    33. -rw-r--r-- 1 user1 user1 0 Jun 15 20:03 ls.out
    34. -rw-r--r-- 1 user1 user1 697 Jun 7 12:25 .profile
    35. -rw-r--r-- 1 user1 user1 741 Jun 7 12:19 .profile.bak
    36. -rw-r--r-- 1 user1 user1 741 Jun 7 13:12 .profile.bak1
    37. -rw-r--r-- 1 user1 user1 0 Jun 15 20:02 test.img
    38. user1@vm1:~$ dd if=/dev/zero of=~/test.img bs=1M count=10
    39. 10+0 records in
    40. 10+0 records out
    41. 10485760 bytes (10 MB) copied, 0.0130061 s, 806 MB/s
    42. user1@vm1:~$ pv ~/test.img | dd if=/dev/stdin of=/dev/null bs=1
    43. 10MB 0:00:03 [3.24MB/s] [=================================================================================>] 100%
    44. 10485760+0 records in
    45. 10485760+0 records out
    46. 10485760 bytes (10 MB) copied, 3.10446 s, 3.4 MB/s
    47. user1@vm1:~$ rm -v foo.out
    48. removed `foo.out'
    49. user1@vm1:~$ rm -v test.img
    50. removed `test.img'
    51. user1@vm1:~$

    解释

    1. 在你的系统上安装pv(管道查看器)程序,稍后你需要它。
    2. 将你的输入读取到变量foo。这是可能的,因为显示器和键盘实际上是系统的电传打字机。是的,那个电传打字机!在线阅读更多关于tty的东西。
    3. 这是你输入的东西。
    4. foo变量的内容重定向到foo.out文件,在进程中创建文件或覆盖现有文件,而不会警告删除所有内容!
    5. 打印出foo.out的内容。
    6. foo变量的内容重定向到foo.out文件,在进程中创建文件或附加 到现有文件。这是安全的,但不要混淆这两者,否则你会有巨大的悲剧。
    7. 再次打印出foo.out内容。
    8. 将空内容重定向到foo.out,在进程中清空文件。
    9. 显示文件确实是空的。
    10. 列出你的目录并将其通过管道输出到grep。它的原理是,获取所有ls -al的输出,并将其扔给grep。这又称为管道。
    11. 将你的目录列出到屏幕上,并写入ls.out。很有用!
    12. 创建大小为 10 兆字节的清零文件。现在不要纠结它如何工作。
    13. 将这个文件读取到/dev/null,这是你系统中终极的垃圾桶,什么都没有。写入它的一切都会消失。请注意,pv会向你展示读取文件的进程,如果你尝试使用其他命令读取它,你就不会知道它需要多长时间来完成。
    14. 删除foo.out。记得自己清理一下。
    15. 删除test.img

    附加题

    • 阅读 stackoverflow 上的管道和重定向,再次阅读 stackoverflow 和 Greg 的 Wiki,这是非常有用的资源,记住它。
    • 打开 bash 的man页面,向下滚动到 REDIRECTION 部分并阅读它。
    • 阅读man pvman tee的描述。