【问题标题】:What is the correct syntax for a bash multi line Heredoc (w/ Sed)?bash 多行 Heredoc(带 Sed)的正确语法是什么?
【发布时间】:2015-06-08 09:27:50
【问题描述】:

在使用 Sed 搜索/插入配置文件时,我遇到了错误。是什么原因造成的,我该如何解决?

我要插入的 Heredoc 可以定义如下:

read -d '' APPLICATION_ENV_STATE <<'EOF'
defined('APPLICATION_ENV') || define('APPLICATION_ENV',(getenv('APPLICATION_ENV') 
    ? getenv('APPLICATION_ENV') : 'production'));
EOF

虽然我的 Sed 命令使用如下变量:

sed -i "/\/\/ \*\* MySQL settings \*\* \/\//i$APPLICATION_ENV_STATE" wp-config.php

结果:

sed: -e expression #1, char 1: unknown command: `?'

除了命令错误后的额外字符。

但是,以下 Heredoc 有效,但在我的文本文件中产生了一些不太漂亮的格式:

read -d '' APPLICATION_ENV_STATE <<'EOF'
defined('APPLICATION_ENV') || define('APPLICATION_ENV', (getenv('APPLICATION_ENV') ? getenv('APPLICATION_ENV') : 'production'));
EOF  

如何让第一个示例工作?

【问题讨论】:

  • 尝试转义问号。 (\?)
  • 看起来$APPLICATION_ENV_STATE 中的换行符是问题所在。

标签: bash sed multiline heredoc


【解决方案1】:

AIUI,问题不在于heredoc,而是了解哪个进程在不同时间做什么。

在运行sed 命令的脚本中,Bash 在sed 甚至看到它之前替换了变量。作为一个多行字符串,它需要转义为sed)。从man page for sed,在i 命令下:

i \     Insert text, which has each embedded newline preceded by a back-slash.

就个人而言,如果可以的话,我建议使用cat 或echo(或像Python / Ruby / PHP 这样的脚本语言),将模板分解为原子元素,因此您可以简单地将相关部分连接在一起。

如果您确实想继续使用当前方法,您至少需要用反斜杠换行符替换换行符 - 尝试类似:

echo $APPLICATION_ENV_STATE | sed 's/$/\\/'

【讨论】:

  • 这是一个绝妙的答案,谢谢。由此,我通过将变量/ Heredoc 修改为:code defined('APPLICATION_ENV') || 得到了我想要的结果。定义('APPLICATION_ENV', (getenv('APPLICATION_ENV') \\ ? getenv('APPLICATION_ENV') : 'production')); EOF code 与我原来的 Sed 命令配合得很好。在这个特定的示例中,我正在使用作为 Wordpress 安装的一部分生成的配置文件,将这些部分分成单独的变量会更有效。再次感谢您的回答:)
  • 尝试投票但不能并尝试格式化我的代码示例,当我尝试对其进行降价时它拒绝了我的更改。不过再次感谢。
  • 很高兴它有帮助。如果它解决了您的问题,请将其标记为已接受的答案(实际上不需要投票,作为新用户,您可能还无法做到这一点)
【解决方案2】:

您使用了错误的工具。您应该在 sed 中使用的唯一结构是 s、g 和 p(带 -n)。只需使用 awk 并避免所有引用/转义的废话:

$ cat file
foo
// ** MySQL settings ** //
bar

$ awk -v app="defined('APPLICATION_ENV') || define('APPLICATION_ENV',(getenv('APPLICATION_ENV')
    ? getenv('APPLICATION_ENV') : 'production'));" '
{print} index($0,"// ** MySQL settings ** //"){print app}' file
foo
// ** MySQL settings ** //
defined('APPLICATION_ENV') || define('APPLICATION_ENV',(getenv('APPLICATION_ENV')
    ? getenv('APPLICATION_ENV') : 'production'));
bar

请注意,您不需要转义要搜索的字符串中的 RE 元字符,因为 awk 可以将字符串视为字符串,并且您不需要转义要添加的字符串中的换行符,并且您不需要带有 shell 变量等的 here doc。

您的 read/sed 命令会因搜索和/或替换字符串中的各种字符组合而失败 - 请参阅 Is it possible to escape regex metacharacters reliably with sed 了解如何在 sed 中稳健地搜索/替换“字符串”,然后只需使用 awk 即可不用担心。

【讨论】:

  • 这是一个强有力的声明,为什么这些是我使用的唯一 Sed 功能? awk 看起来也不错。
  • 我使用 sed 已经 30 多年了,使用 awk 大约有 20 年了,所有其他 sed 构造都用于 awk 构造可以更简单、简单、稳健、高效、可扩展地完成的功能,始终如一,等等。 sed 是用于在单个行上进行简单替换的出色工具,但是在 1970 年代中期,您需要安排在不太可能的配置中以对文本产生一次性影响的所有其他神秘的单字符 sed 语言结构已经过时了awk 是什么时候发明的。有关示例,请参阅awk.info/?doc/tip/sedInAwk.html。
  • 我会看看那个。我一直在尝试做的一件事是让我的脚本尽可能整洁,对我来说,这意味着将这些字符串存储到文件顶部的配置文件中,远离脚本的逻辑。您提到我的读取命令也可能因某些字符串模式而失败?您将如何获得这样存储的多行变量? (在某处看到另一个堆栈溢出答案后,我最初选择了read -d '')。
  • 任何时候你在shell中写一个读命令你都应该使用IFS= read -r var,除非你有特定的理由排除IFS=或者-r并且完全理解它的效果。如果您要读取的字符串以空格开头或包含反斜杠,请尝试您当前的方法,您会发现它会去除前导空格和反斜杠。 Shell 不适用于处理文本,因此很难稳健地进行操作。写 shell 的人也写 awk 正是为了操作文本。如果没有示例,我不确定该给出什么建议 - 新问题?
  • 这个例子已经在我的问题中了;我将heredoc读入一个变量。尽管您提到 read/sed 命令在某些情况下可能会失败。我将不得不查找读取命令和 IFS 变量(我以前使用过,但它的用途目前不知道)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-11-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-04-25
  • 2016-10-28
相关资源
最近更新 更多