【问题标题】:sed substitute variable contains newline (preserve it)sed 替代变量包含换行符(保留它)
【发布时间】:2016-09-01 18:13:06
【问题描述】:

我有一个多行字符串,从网上下载的:

toast the lemonade
blend with the lemonade
add one tablespoon of the lemonade
grill the spring onions
add the lemonade
add the raisins to the saucepan
rinse the horseradish sauce

我已将此分配给$INPUT,如下所示:

INPUT=$(lynx --dump 'http://example.net/recipes' \
     | python -m json.tool \
     | awk '/steps/,/]/' \
     | egrep -v "steps|]" \
     | sed 's/[",]\|^ *//g; $d')

此时,$INPUT 已准备好替换到我的目标文件中,如下所示:

sed -i "0,/OLDINPUT/s//$INPUT/" /home/test_file

当然,sed 抱怨一个未终止的s 命令——这就是问题所在。

我正在使用的当前解决方法是在将其提供给 sed 之前将 echo $INPUT 发送给 echo $INPUT,但随后不会保留换行符。 echo 去除换行符 - 这就是问题所在。

正确的输出应该保持它的换行符。如何指示 sed 保留换行符?

【问题讨论】:

  • unterminated 's' 几乎总是意味着您的“数据”中有一个“/”字符。只需使用不同的字符来分隔s@string@repl@[g]。 Posix sed 期望 \@string@repl@。注意前导反斜杠字符。祝你好运。
  • @shelter 这将如何工作? sed -i "0,/OLDINPUT/s//$INPUT/" /home/test_file 喜欢吗? sed -i "0,@OLDINPUT/s@/$INPUT@" /home/test_file
  • 我相信你需要\@matchInput@s@string@repl@ 当然你的$INPUT 不能有任何@ 字符。如果是这样,请使用~ 或不在$INPUT 中的其他内容。因此,您将使用/ 的任何地方现在都需要成为您的新分隔符。祝你好运。
  • 在重读您的问题后,请澄清一下,您的目标是通过sed 插入多行文本($INPUT)吗?这需要使用sedi(插入)或a(追加)命令。在尝试使用变量之前,您应该在更简单的环境中使用它。 (不推荐!)对不起,但是/祝你好运!
  • @shelter,输入是逐行的,这就是我尝试使用 sed 替换替换/插入的内容。问题是它仅在我使用 echo 将输入更改为一行而不是逐行时才有效 - 这是 sed 工作的唯一方式...

标签: sed


【解决方案1】:

直接的答案是用\n 替换所有换行符,您可以通过添加来做到这一点

| sed ':a $!{N; ba}; s/\n/\\n/g'

到上面的长命令。一个更好的答案是使用 awk 代替,因为将 shell 变量替换为代码总是一个坏主意,并且使用 sed 你别无选择:

awk -i inplace -v input="$INPUT" 'NR == 1, /OLDINPUT/ { sub(/OLDINPUT/, input) } 1' /home/test_file

-i inplace 需要 GNU awk 4.1.0 或更高版本。

【讨论】:

  • 您好,谢谢!我尝试将:| sed ':a $!{N; ba}; s/\n/\\n/g' 附加到长命令,但仍然得到:sed: -e expression #1, char 30: unterminated s' command (tried again) sed: -e expression #1, char 28: unterminated s' command
  • 这里是您添加的命令示例:(请注意,它仍然无法通过 sed 部分)...[root@test]# lynx --dump 'http://somesite.net/recipe/' | python -m json.tool | awk '/steps/,/]/' | egrep -v "steps|]" | sed 's/"//g' |sed 's/,//g' | sed 's/^ */ /g' | sed '$d' | sed ':a $!{N; ba}; s/\n/\\n/g' 筛选咖啡\n烧烤黄瓜\n将黄瓜煮沸\烤鱼肝油\n把黄瓜煮沸\n炒泡菜\n加一汤匙泡菜
  • 为我工作。嗯...您不会碰巧使用 Mac OS X 或 *BSD,对吗?
【解决方案2】:

如果您使用的是 Bash,则可以将 \n 替换为换行符:

INPUT="${INPUT//
/\\n}"

如果您不喜欢参数扩展中的文字换行符,您可能更喜欢

INPUT="${INPUT//$'\n'/\\n}"

旁注 - 您可能的意思是 change 匹配的行到您的输入,而不是 substitute 每个。在这种情况下,你不想引用换行符,毕竟......

【讨论】:

    【解决方案3】:

    清理你的代码一些。

    这个:

    lynx --dump 'http://somesite.net/recipes' | python -m json.tool | awk '/steps/,/]/' | egrep -v "steps|]" | sed 's/"//g' |sed 's/,//g' | sed 's/^ *//g' | sed '$d'
    

    可以用这个代替:

    lynx --dump 'http://somesite.net/recipes' | python -m json.tool | awk '/]/ {f=0} f {if (c--) print line} /steps/{f=1} {gsub(/[",]|^ */,"");line=$0}'
    

    它可能会更短,但我现在不知道这是做什么的:python -m json.tool

    这个:

    awk '/]/ {f=0} f {if (c--) print line} /steps/{f=1} {gsub(/[",]|^ */,"");line=$0}'
    

    做:

    1. 将模式steps 之后的行打印到] 之前的行 - awk '/steps/,/]/' | egrep -v "steps|]"
    2. 删除", 和所有行前的所有空格。 - sed 's/"//g' |sed 's/,//g' | sed 's/^ *//g'
    3. 然后删除该组的最后一行。 - sed '$d'

    例子:

    cat file
    my data
    steps data
     more
     do not delet this
    hei "you" , more data
    extra line
    here is end ]
    this is good
    

    awk '/]/ {f=0} f {if (c--) print line} /steps/{f=1} {gsub(/[",]|^ */,"");line=$0}' file
    more
    do not delet this
    hei you  more data
    

    【讨论】:

    【解决方案4】:

    假设您的输入 JSON 片段如下所示:

    { "other": "random stuff",
      "steps": [
        "toast the lemonade",
        "blend with the lemonade",
        "add one tablespoon of the lemonade",
        "grill the spring onions",
        "add the lemonade",
        "add the raisins to the saucepan",
        "rinse the horseradish sauce"
      ],
      "still": "yet more stuff" }
    

    您可以只提取steps 成员

    jq -r .steps
    

    要将其插入到sed 语句中,您需要转义结果中的任何正则表达式元字符。从标准输入读取静态文本是一个不那么令人生畏并且希望稍微不那么骇人听闻的解决方案:

    lynx ... | jq ... |
    sed -i -e '/OLDINPUT/{s///; r /dev/stdin' -e '}' /home/test_file
    

    教育从业人员使用结构感知工具来处理结构化数据的努力已达到epic 的高度,并且有增无减。在您决定使用快速而肮脏的方法之前,至少要确保您了解危险(技术和心理)。

    【讨论】:

      【解决方案5】:

      您需要使用编辑器而不是 sed 的替换:

      $ input="toast the lemonade
      blend with the lemonade
      add one tablespoon of the lemonade
      grill the spring onions
      add the lemonade
      add the raisins to the saucepan
      rinse the horseradish sauce"
      
      $ seq 10 > file
      
      $ ed file <<END
      1,/5/d
      1i
      $input
      .
      w
      q
      END
      
      $ cat file
      toast the lemonade
      blend with the lemonade
      add one tablespoon of the lemonade
      grill the spring onions
      add the lemonade
      add the raisins to the saucepan
      rinse the horseradish sauce
      6
      7
      8
      9
      10
      

      【讨论】:

      • 不,问题是sed "s/string/$INPUT/" 在换行符处换行。您必须反斜杠 $INPUT 中的所有换行符才能使 sed 变得可口。
      • 啊,我明白了。 ed救援
      • @glennjackman 非常感谢您的意见。你肯定一针见血。您的解决方案唯一要做的是,在将其传递给 sed 之前,我需要以编程方式处理它。这一切都是从一个 shell 脚本运行的......
      • ed 可以很容易地编写脚本,正如我所演示的:将所需的命令传递给标准输入上的 ed。
      猜你喜欢
      • 1970-01-01
      • 2023-01-24
      • 1970-01-01
      • 2013-05-11
      • 1970-01-01
      • 2013-08-22
      • 2021-12-18
      • 2012-02-14
      • 1970-01-01
      相关资源
      最近更新 更多