【问题标题】:How to redirect and replace the input file with the output (don't erase myfile when doing "cat myfile > myfile")如何重定向输入文件并将其替换为输出(执行“cat myfile > myfile”时不要删除 myfile)
【发布时间】:2014-01-31 23:47:44
【问题描述】:

重定向到用作输入的文件并替换文件而不是删除文件的正确方法是什么? 我想做类似的事情:

cat myfile > myfile

程序(即cat)读取文件然后重定向到文件的位置,因此在上面的示例中myfile 将保持不变。

我知道上面的例子会删除文件as explained here

什么是正确的语法,所以文件将被替换而不是被删除?是否可以进行标准输出和重定向,或者程序是否应该处理打开新数据并将其写入文件?我想让我的程序将输出发送到标准输出,然后用户可以重定向或管道或其他任何东西。

顺便说一句,我不想​​>>(连接)。我希望左边的函数将“新”数据写入文件——替换文件内容。

也许更好的说法是我希望重定向的左侧在流式传输发生之前完全发生——这可能吗?我对 bash 有根本的误解吗?

【问题讨论】:

  • 你的新文件的名称是什么?
  • @adrin,在上面的例子中'myfile'
  • 我的意思是,如果不是“附加”数据,什么是“新”数据?

标签: bash redirect sh


【解决方案1】:

您必须先将所有数据读入内存,或者写入临时文件并将其换出。

将其读入内存(如vimed 和其他编辑器):

contents=$(<myfile)
cat <<< "$contents" > myfile

要创建一个临时文件(如sed -irsync 和其他更新工具):

tmpfile=$(mktemp fooXXXXXX)
cat myfile > "$tmpfile" && mv "$tmpfile" myfile

【讨论】:

  • 可能值得确保mktemp 在与原始目录相同的目录中创建其临时文件,以便mv 只是重命名而不是复制和删除。我通常使用myfile.$$ 作为中间文件(参见my answer)。
  • @KeithThompson 这就是给定模式会发生的事情,而不假设名为 myfile.pid 的文件永远不存在。
  • 是的——假设myfile 在当前目录中。如果我们从字面上看示例命令,那不是问题,但如果 myfile 被某个绝对或相对路径名替换,则可能是。如果$$ 不够独特,您可以使用$(mktemp myfileXXXXXX),或更一般地使用$(mktemp ${filename}XXXXXX)
【解决方案2】:

大概你有兴趣做一些比cat myfile更复杂的事情。

某些命令具有命令行参数,可让您执行此操作(通常为 -i)——但这些选项通过写入临时文件然后重命名临时文件来工作。

你可以自己做同样的事情:

cat myfile > myfile.$$ && mv myfile.$$ myfile

我经常使用$$,它扩展为我的shell 的进程ID,作为临时文件的后缀;这使得该名称不太可能与其他文件发生冲突。

使用&amp;&amp; 意味着它不会破坏您的输入文件,除非cat 命令成功。

这种方法的一个可能问题是您的新文件myfile.$$ 是一个新创建的文件,因此它不会保留原始输入文件的权限。如果你有chmod 命令的GNU Coreutils 版本,你可以避免这个问题:

cat myfile > myfile.$$ && \
    chmod --reference=myfile myfile.$$ && \
    mv myfile.$$ myfile

【讨论】:

  • 谢谢,这很好,我喜欢使用 $$。我可能会接受thatotherguy的回答,因为他展示了两种方法。但我喜欢 $$ 的用法,也许您可​​以将其添加到他的答案中?
  • 是的,我有兴趣做一些比 cat 更有趣的事情 :-) 我盯着看了好几个小时,想知道为什么我的程序在尝试重定向时会读取 0 字节,但是当我将 find 打印到标准输出时没有重定向。菜鸟错误...
【解决方案3】:

我在这里按字面意思回答你的问题。通过引入管道读取 cat 的输出,第二个管道进程从 stdin 读取输出并将其重定向到原始文件名,从而产生一个未更改的文件:

cat myfile | cat - > myfile

危险:这是一个竞争条件。在第二个进程使用输出重定向截断它之前,不能保证第一个进程可以读取 myfile 的整个 cmets。

【讨论】:

  • 感谢您的提示。在我的特殊情况下,我已经将 stdin 用于另一个目的(基本上是以“特殊”方式添加文件的信息)。但是,这可能在将来有用,它确实回答了这个问题。谢谢!
  • 确定这是 100% 可靠的吗?比赛条件可能会产生令人惊讶的结果。
  • 如果成功了,恭喜你,你赢得了比赛条件。在第二个进程使用输出重定向截断它之前,不能保证第一个进程可以读取myfile 的整个 cmets。
  • [重发2014-02-01之前的评论并删除失效链接]:除了其他问题,-是不必要的; cat 本身等价于 cat -(如果您不指定任何文件名,catstdin 读取)。如果您想连接stdin 一个或多个文件的内容,- 参数很有用。 (无用的连字符?)
猜你喜欢
  • 2011-02-04
  • 2014-12-12
  • 2019-03-21
  • 2012-07-15
  • 2023-03-20
  • 1970-01-01
  • 2013-06-20
  • 2022-08-07
  • 1970-01-01
相关资源
最近更新 更多