echo "hello" >&0 | > file.txt 没有写入 file.txt

echo "hello" >&0 | > file.txt 没有写入 file.txt

我正在学习基本的终端命令。

为什么这个命令没有按照我预期的那样工作?

echo "hello" >&0 | > file.txt

我知道我可以简单地打字echo "hello" > file.txt ,但我正在学习使用管道。我只想将单词“hello”输出到文件中。

答案1

在 bash 中,带有重定向的空命令只会以与重定向相关的方式打开文件,然后关闭它*。是一个由两个简单命令, ,echo "hello" >&0 | > file.txt组成的复合命令。第二个命令是空的,因此 bash 只会打开文件进行写入、截断它,然后关闭它。echo "hello" >&0> file.txt

在终端中,通常标准输入、输出和错误都连接到终端。因此,当您将 stdout 重定向到 stdin 时,它仍然指向终端,并且的输出echo hello >&0在终端中可见,并且根本不发送到管道。

在 zsh 中,带有重定向的空命令默认为cat命令。因此echo "hello" >&0 | > file.txt实际上是echo "hello" >&0 | cat > file.txt,您将看到想要的效果。这在 bash 中是不可能的。在这里,您将看到 bash 中没有的另一个重定向功能:当您多次重定向命令的输出时,输出将发送到每个重定向目的地(因此将hello同时发送到终端和管道)。在 bash 中,它仅发送到最后一个重定向位置。


* 例外情况是命令替换使用重定向的标准输入。在 中$(<some-file),bash 将读取 的内容some-file并将其用作命令替换的值。

答案2

啊,我明白你在想什么了(我想)。你试过了

echo hello | > file

并且什么也没发生file,所以你想,也许我需要通过重定向将命令的输出转换为标准输入:

echo hello >&0 

但将 stdout 转换为 stdin 正是管道所做的。它获取 stdout 并将其作为 stdin 传递给其右侧的命令。如果重定向 stdout,则不会通过管道传输任何内容:

$ echo hello >&0 | cat > file
hello
$ cat file
$

(空空如也)

但是hello在终端中,它像往常一样从标准输入读取:

$ cat /dev/fd/0
hi
hi
I am talking to myself!
I am talking to myself!

等等...

如果我们不重定向...

$ echo hello | cat > file
$ cat file
hello

的标准echo hello输出通过管道(而不是到终端)并成为的标准输入cat

因此,管道会执行您想要执行的操作(将 stdout 转换为 stdin 并将其连接到正确的命令),您不必通过摆弄文件描述符来自己完成这些操作。

至于为什么带有重定向的空命令不能完成您想要的操作,参见 muru 的回答

答案3

我猜您也想将输出写入文件和标准输出。

echo hello > file.txt 

部分执行此操作,但它会跳过标准输出(不会在控制台上打印任何内容)。如果您也想要这样做,请使用tee以下命令:

echo hello | tee file.txt

它将 的输出通过管道传输echo到 的输入tee,然后 tee 将内容写入屏幕并写入 file.txt 中。

如果您只想打印到文件,请使用cat以下命令:

echo hello | cat >file.txt

另请查看此答案以了解重定向的工作原理:https://stackoverflow.com/a/818265/5771279

管道的工作原理如下:https://stackoverflow.com/a/9834118/5771279

也查看tee命令的手册页。

答案4

  • >符号用于将文件重定向至文件开头。
  • >>符号用于将文件重定向到文件末尾(附加)。
  • |符号表示“管道”或将一个命令的输出作为另一个命令的输入传递。

    $ echo "Hello" > file.txt
    $ echo "World!" >> file.txt
    $ cat file.txt
    Hello
    World!
    $ cat file.txt | grep !
    World!
    

(全局正则表达式打印)命令grep在文件中搜索给定的搜索字符串并打印其所在的行。

根据&>0高级 Bash 脚本指南

&>filename
  # Redirect both stdout and stderr to file "filename."
  # This operator is now functional, as of Bash 4, final release.

在您的例子中,文件名是 0,即标准输入。因此它将所有输出重定向到输入。据我所知,这是一个无法正常工作的循环引用。您使用的语法是>&0将输出重定向到输入。这似乎也是一个循环引用。

“文件名”为:

  • 0标准输入
  • 1标准输出
  • 2标准错误输出

通过文件重定向使用文件描述符(标准输入)的传统方式0是:

 0< FILENAME
    < FILENAME
      # Accept input from a file.
      # Companion command to ">", and often used in combination with it.
      #
      # grep search-word <filename

如果您想一起使用echo命令和|(正如 Zanna 的回答指出的那样),您可以使用:

$ echo "hello" | cat > file.txt
$ cat file.txt
hello

相关内容