输入重定向如何工作?

Alp*_*ega 7 command-line bash

是的,我已经尝试在其他地方查找它,但是应该说明输入重定向的示例,例如这里,总是有一个令人困惑的警告。在刚刚发布的网站示例中,他们说:

  # echo 'hello world' >output
  # cat <output
Run Code Online (Sandbox Code Playgroud)

第一行将“hello world”写入文件“output”,第二行将其读回并将其写入标准输出(通常是终端)。

但是,cat output会做完全相同的事情,<这里没有。那么区别是什么呢??

ter*_*don 8

输入重定向(如cat < file)意味着shell正在打开输入文件并将其内容写入另一个进程的标准输入。将文件作为参数传递(正如您在运行时所做的那样cat file)意味着您正在使用的程序(例如cat)需要打开文件本身并读取内容。

基本上,command file文件传递给commandcommand < file文件的内容传递给command. 是的,在像cat filevscat < file这样的情况下,结果没有容易察觉的差异,但是两者的工作方式不同。

要了解其中的区别,请考虑一个年幼的孩子和一个成年人。两个人都可以喝水。但是,大人可以打开水龙头装满玻璃杯(打开文件并阅读其中的内容),而孩子则需要直接给水(它无法打开文件,只能处理其中的内容)。

某些程序,例如cat,能够将文件名作为输入,然后打开文件并对其进行处理。这就是为什么cat file有效。但是,其他程序不知道什么是文件或如何使用它们。他们只知道输入流(比如文件的内容)。例如tr

$ cat file
foo
$ cat file | tr 'o' 'b'  ## tr can read a stream
fbb
$ tr 'o' 'b' file  ## tr can't deal with files
tr: extra operand ‘file’
Try 'tr --help' for more information.
$ tr 'o' 'b' < file ## input redirection!
fbb
Run Code Online (Sandbox Code Playgroud)

另一个例子是ls它可以很好地处理文件,但忽略输入流:

$ ls
file1  file2
$ ls file1   ## lists only file1: ls takes file names as arguments
file1
$ ls < file1 ## ls ignores its standard input, this is the same as ls alone
file1 file2
Run Code Online (Sandbox Code Playgroud)

其他程序无法处理流,而是需要文件:

$ rm < file ## fails, rm needs a file 
rm: missing operand
Try 'rm --help' for more information.
$ rm file ## works, file is deleted
Run Code Online (Sandbox Code Playgroud)

一些程序可以处理打开文件和读取输入流,但它们的行为方式不同。例如,wc当给定要打开的文件时,它会打印文件名以及行数、单词数和字符数:

$ wc file
1 1 4 file
Run Code Online (Sandbox Code Playgroud)

但是,如果我们只是给它一个流,它无法知道这是来自特定文件,因此不会打印文件名:

$ wc < file
1 1 4
Run Code Online (Sandbox Code Playgroud)

md5sum命令的行为类似:

$ md5sum file
17fd54512c91e3cd0f70fbaaa9a94d0d  file
$ md5sum < file
17fd54512c91e3cd0f70fbaaa9a94d0d  - 
Run Code Online (Sandbox Code Playgroud)

请注意,在第一种情况下显示文件名file,而在第二种情况下,“文件名”是-:标准输入。


现在,如果您想了解更多详细信息,您可以使用它strace来查看到底发生了什么:

strace -e trace=open,close,read,write wc file 2>strace1.txt
Run Code Online (Sandbox Code Playgroud)

strace -e trace=open,close,read,write wc < file 2>strace2.txt
Run Code Online (Sandbox Code Playgroud)

那些将所有的所有细节open()close()read()操作由进程中运行。您想看到的是strace1.txt(当文件作为参数传递而不是输入重定向时)包含以下几行:

open("file", O_RDONLY)                  = 3
read(3, "foo\n", 16384)                 = 4
Run Code Online (Sandbox Code Playgroud)

这些意味着文件file被打开并附加到文件描述符3。然后,从foo\n中读取字符串3strace使用输入重定向时输出的等效部分是:

read(0, "foo\n", 16384)                 = 4
Run Code Online (Sandbox Code Playgroud)

没有相应的open()调用,而是foo\n0标准输入1读取字符串。


1 默认情况下,0是标准输入、1标准输出和2标准错误。顺便说一下,这就是为什么file打开为3,那是下一个可用的。