【问题标题】:Using the same file for stdin and stdout with redirection对 stdin 和 stdout 使用相同的文件并进行重定向
【发布时间】:2010-10-09 19:01:23
【问题描述】:

我正在编写一个类似于过滤器的应用程序:它从文件 (stdin) 读取输入、处理并将输出写入另一个文件 (stdout)。在应用程序开始写入输出文件之前,输入文件被完全读取。

由于我使用的是标准输入和标准输出,所以我可以运行是这样的:

$ ./myprog <file1.txt >file2.txt

它工作正常,但如果我尝试使用相同的文件作为输入和输出(即:从一个文件中读取,并写入同一个文件),像这样:

$ ./myprog <file.txt >file.txt

它在程序有机会读取它之前清除file.txt

有什么方法可以在 Unix 的命令行中做这样的事情吗?

【问题讨论】:

    标签: unix pipe


    【解决方案1】:

    moreutils 包中有一个海绵实用程序:

    ./myprog < file.txt | sponge file.txt
    

    引用手册:

    Sponge 读取标准输入并将其写入指定文件。与 shell 重定向不同,海绵在打开输出文件之前会吸收所有输入。这允许构建读取和写入同一文件的管道。

    【讨论】:

    • 请详细说明你的答案。
    【解决方案2】:

    shell 会破坏您的输出文件,因为它在执行您的程序之前 准备输出文件句柄。没有办法让你的程序在 shell 在单个 shell 命令行中破坏文件之前读取输入。

    您需要使用两个命令,在读取文件之前移动或复制文件:

    mv file.txt filecopy.txt
    ./myprog < filecopy.txt > file.txt
    

    或者输出到副本然后替换原件:

    ./myprog < file.txt > filecopy.txt
    mv filecopy.txt file.txt
    

    如果你不能这样做,那么你需要将文件名传递给你的程序,它以读/写模式打开文件,并在内部处理所有 I/O。

    ./myprog file.txt                 # reads and writes according to its own rules
    

    【讨论】:

      【解决方案3】:

      对于纯学术性质的解决方案:

      $ ( unlink file.txt && ./myprog >file.txt ) <file.txt
      

      可能有问题的副作用是:

      • 如果./myprog 失败,您会破坏您的输入。 (当然……)
      • ./myprog 从子shell 运行(使用{ ... ; } 而不是( ... ) 来避免。)
      • file.txt 成为具有新 inode 和文件权限的新文件
      • 您需要拥有file.txt 目录外壳的+w 权限。

      【讨论】:

      • 奇怪。为什么 $ (./myprog &gt;file.txt) &lt;file.txt 不工作而删除 file.txt 首先工作?
      • 您的示例这样做是因为 &gt;file.txt 截断了 file.txt 的内容,而这恰好是 &lt;file.txt 正在读取的同一文件。 (这在原始问题和接受的答案中提到,并且使用子外壳不会改变这一点。)通过首先取消链接,&gt;file.txt 创建一个 新文件 (不同的 inode 在相同的路径)与 &lt;file.txt 正在读取的内容是分开的。
      • 所以我们要做的就是自己运行子shell。我想我知道答案,但我仍然不确定为什么......
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-04-18
      • 1970-01-01
      • 2017-09-07
      • 2018-05-30
      相关资源
      最近更新 更多