【问题标题】:prepend **heredoc** to a file, in bash在 bash 中将 **heredoc** 添加到文件中
【发布时间】:2014-08-29 07:29:55
【问题描述】:

我正在使用:

cat <<<"${MSG}" > outfile

首先向outfile 写消息,然后继续进行进一步处理, 它从我的 awk 脚本中附加到 outfile

但是现在我的程序中的逻辑发生了变化,所以我必须先填充 outfile 通过附加我的 awk 程序中的行(从我的外部调用 bash 脚本),然后作为最后一步添加 ${MSG} heredoc 到 我的outfile..的负责人..

我怎样才能在我的 bash 脚本而不是 awk 脚本中做到这一点?

编辑

这是味精heredoc:

read -r -d '' MSG << EOF
-----------------------------------------------
--   results of processing - $CLIST
--   used THRESHOLD ($THRESHOLD)
-----------------------------------------------
l
EOF
# trick to pertain newline at the end of a message
# see here: http://unix.stackexchange.com/a/20042
MSG=${MSG%l}

【问题讨论】:

  • 注意:带异端的猫?可移植的方法是printf '%s\n' "$MSG" &gt; outfile。尽可能避免使用 bashism。
  • 仅供参考,您在这里所做的必然是低效的——“必然”意味着 POSIX 不提供任何方式(在 any 编程语言中)将内容添加到一个文件而不重写整个文件。如果它是一个大文件,那么,你应该尽量避免任何会让你经常这样做的过程。
  • @CharlesDuffy 是的,你是对的,在我的脚本中这只发生了一次。我尝试使用awk 处理该MSG 写作,但是,由于awk 脚本在我的bash 脚本中被多次调用,将MSG 放入BEGIN 块无济于事,因为我会有很多实例,我只想要一个在顶部。
  • 顺便说一句:你可以不用l 保留尾随换行符的技巧,如果你使用以下代码:IFS= read -r -d '' MSG &lt;&lt; EOF ...
  • @mklement0 我是否必须将其恢复为旧的 IFS 值,或者没关系,因为它会随着脚本的完成而发生?

标签: bash prepend herestring


【解决方案1】:

使用命令组:

{
    echo "$MSG"
    awk '...'
} > outfile

如果outfile 已经存在,您别无选择,只能使用临时文件并将其复制到原始文件上。这是由于所有(?)文件系统如何实现文件;您不能预先添加到流中。

{
     # You may need to rearrange, depending on how the original
     # outfile is used.
     cat outfile
     echo "$MSG"
     awk '...'
} > outfile.new && mv outfile.new outfile

您可以与 cat 一起使用的另一个非 POSIX 功能是进程替换,它使任意命令的输出看起来像 cat 的文件:

cat <(echo $MSG) outfile <(awk '...') > outfile.new && mv outfile.new outfile

【讨论】:

  • 我不能这样做,因为这发生在我已经生成了 outfile 的那一刻。我有一个案例检查outfile 是否存在,如果存在,那么我需要预先添加我的 $MSG
  • 我确实做到了:cat &lt;&lt;&lt; $MSG outfile &gt; outfile.tmp &amp;&amp; mv outfile.tmp outfile,但最终outfile 为空,并且我的目录中仍然有outfile.tmp?这就是我在这里发布问题的原因;)
  • 我的错.. 现在我看到了,在 mv outfile.tmpoutfile 之间输入了 &gt;,监督这一点,导致我在这里发帖.. 抱歉耽误您的时间
  • 不知道为什么,但是cat &lt;&lt;&lt; $MSG outfile &gt; outfile.tmp &amp;&amp; mv outfile.tmp outfile 没有前置$MSG,outfile 有,但是没有前置$MSG?
  • &lt;&lt;&lt; 提供标准输入,cat 在接收到一个或多个文件名参数时忽略标准输入。
【解决方案2】:

您可以使用awk 在文件开头插入多行字符串:

awk '1' <(echo "$MSG") file

或者甚至这个echo 应该可以工作:

echo "${MSG}$(<file)" > file

【讨论】:

  • $MSG 包含多行,是heredoc 类似横幅的消息
  • MSG 变量实际上可以有任意数量的行。 awk 的substr 函数已用于从前面剥离$' 和从末尾剥离\n'(它们是由printf "%q" 添加的)。在发布答案之前,我已经在我的 OSX 上对其进行了测试。
  • +1 用于简单的解决方案,但您应该注意 (a) awk 不是这项工作的正确工具一般而言 - 这里有意义 特别是,因为 OP 的特定要求,以及 (b) echo 解决方案应该只用于 small 文件,因为整个字符串是在内存中构建的(对吗?)。另外,听起来$MSG 已经被\n 终止了,所以你应该使用&lt;(printf '%s' "$MSG")
  • @CharlesDuffy:结束讨论,尽管printf %q 不再参与其中:我同意你的担忧;例如,如果字符串恰好不包含需要转义的字符(尽管在这种情况下会转义),printf %q 的结果是 not $'...'-enclosed。请注意,GNU awkmawk 实际上在命令行上接受带有嵌入换行符的字符串 - FreeBSD/OSX awk 不接受(这实际上是符合 POSIX 的行为)。符合awk-POSIX 的解决方案是用'\n' 字符串替换换行符:`-v MSG="${MSG//$'\n'/\\n}"。请参阅goo.gl/uT1oh9 了解更多信息。
  • 被严重低估的答案。谢谢!为了完成,echo 版本只是进入标准输出 - 它不会重写原始文件(根据问题)。调整很简单:echo "${MSG}$(&lt;file)" &gt; file
【解决方案3】:

使用- 作为cat 命令行上的占位符,用于插入新内容的位置:

{ cat - old-file >new-file && mv new-file old-file; } <<EOF
header
EOF

【讨论】:

  • 可以将&lt;&lt;EOF 部分替换为&lt;&lt;&lt;"${MSG}",因为我已经这样了吗?
  • +1 表示前缀形式,但使用cat &lt;&lt;EOF &gt;&gt;old-file 表示后缀形式更简单。
  • @mklement0,确实,这很愚蠢。我已将其删除。
  • @branquito,确实,使用这里的字符串就可以了。
  • @branquito,目前的答案没有任何问题,即使这个答案更干净一点,保留它也很好。
猜你喜欢
  • 1970-01-01
  • 2019-08-05
  • 2021-08-09
  • 2011-02-26
  • 1970-01-01
  • 2021-09-02
  • 2018-10-01
  • 2020-03-27
  • 1970-01-01
相关资源
最近更新 更多