【问题标题】:In bash script, is it possible to echo something into the beginning of file?在 bash 脚本中,是否可以将某些内容回显到文件的开头?
【发布时间】:2013-10-30 18:30:40
【问题描述】:

我知道

回显文本 >> file.txt

我可以将“文本”附加到文件 file.txt 的末尾

但是是否可以在文件开头插入一些内容而不删除现有内容?

谢谢,

【问题讨论】:

  • 否;无论您使用什么技术,它本质上都与{ echo text; cat file.txt; } > new_file.txt && mv new_file.txt file.txt 相同。您可以在不影响现有内容的情况下对文件进行的唯一更改是将数据添加到末尾。

标签: bash file shell echo


【解决方案1】:

你可以使用 cat 和一个临时文件:

echo 'text' | cat - file.txt > temp && mv temp file.txt

【讨论】:

    【解决方案2】:

    您可以使用ed,标准编辑器:

    stuff="this is the stuff you want to prepend to file"
    ed -s file.txt < <(printf '%s\n' 1 i "$stuff" . wq) > /dev/null
    

    如果要添加多行,请将它们放在一个数组中,如下所示:

    stuffs=( "this is the first line you want to prepend to file" "lalala the second line" "my gorilla loves bananas in this third line" )
    ed -s file.txt < <(printf '%s\n' 1 i "${stuffs[@]}" . wq) > /dev/null
    

    唯一的限制是插入仅包含单个句点的行。叹息。

    ed 是标准编辑器。此方法不涉及临时文件!如果您选择此方法,您将真正编辑文件(因此您不会更改权限和所有权)。这可能是最有效的方法之一。一种更有效的方法(用于 huuuuge 文件)是直接处理dd。但你肯定不希望这里出现。

    正如 Georgi Kirilov 在下面的 cmets 中建议的那样,您可以使用此方法而无需任何 bashism,如下所示:

    stuffs=( "I love oranges, but my gorilla loves bananas" )
    printf '%s\n' 1 i "$stuff" . wq | ed -s file.txt > /dev/null
    

    如果您的系统带有printf(而且很有可能确实如此)。

    【讨论】:

    • 您的解决方案会在一些没有 GNU 的古老系统上击败其他解决方案(bash 的 $(&lt;) 和 sed 的 -i),但我相信 &lt;() 语法仍然是 bash。像下面这样的东西会更“标准”:printf "1\ni\n${stuff}\n.\nwq\n" | ed file.txt
    • @GeorgiKirilov 是的,我喜欢 bash 的语法。不过,会将您的建议添加到答案中。谢谢。
    • 当您在没有创建临时文件权限的目录中写入您确实具有写权限的文件时,ed 可用,而 sed 根本不可用。
    【解决方案3】:

    是的,你可以通过 sed 来实现:

    sed -i '' '1i\
    some-text
    ' file
    

    或者使用 awk:

    awk -v T=some-text 'NR==1{print T} 1' file
    

    无需任何外部实用程序:

    echo -e "some-text\n$(<file)" > file
    

    【讨论】:

    • sed -i 仍然会创建一个临时文件,然后将其移动到旧文件上。您的第三个示例将不起作用,或者至少只有在 $(&lt; file) 在被 &gt; file 截断之前完全读取文件的内容时才会起作用。
    • @chepner:谢谢,我知道 sed 创建了一个临时文件,然后将它移过来。但是为什么这是一个问题,因为所有 OP 想要的是在第一行之前插入一些内容。
    • @chepner ...哇,真的吗? &gt; file 真的会在任意限制后截断流吗?即丢弃发送给它的内容?
    • @Ajax 没有任意限制; &gt; file completelyanything else 写入之前截断文件。这里的问题是,在&gt; file截断之前,shell进程$(&lt;file)是否将整个文件读入内存并没有很好的定义。
    • 我的理解是&gt; redirect每个定义的进程一次截断它...例如,exec &gt; &gt;( grep -v "blah" | tee &gt; some_file) 会将所有标准输出重定向到 tee,这将截断第一次写入,然后继续追加。我想也许我错过了什么。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-02-19
    • 2012-02-05
    • 1970-01-01
    • 2011-05-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多