sed substitute variable contains newline (preserve it)

I have a multi-line string, downloaded from the Web:

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

I have assigned this to $INPUT , like this:

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

At this point, $INPUT is ready for substitution into my target file as follows:

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

Of course, sed complains about an unterminated s command - herein lies the problem.

The current workaround I am using is to echo $INPUT prior to giving it to sed, but then the newlines are not preserved. echo strips newlines - which is the problem.

The correct output should maintain its newlines. How can sed be instructed to preserve the newlines?


The hacky direct answer is to replace all newlines with n , which you can do by adding

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

to the long command above. A better answer, because substituting shell variables into code is always a bad idea and with sed you wouldn't have a choice, is to use awk instead:

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

This requires GNU awk 4.1.0 or later for the -i inplace .


To clean up your code some.

This:

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'

Can be replaced with this:

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

It may be shorten more, but I do not now what this does: python -m json.tool

This:

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

Does:

  • Print line after pattern steps to line before ] - awk '/steps/,/]/' | egrep -v "steps|]" awk '/steps/,/]/' | egrep -v "steps|]"
  • Removes " , , and all space in front of all lines. - sed 's/"//g' |sed 's/,//g' | sed 's/^ *//g' sed 's/"//g' |sed 's/,//g' | sed 's/^ *//g'
  • Then remove last line of this group. - sed '$d'

  • Example:

    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
    

    Assuming your input JSON fragment looks something like this:

    { "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" }
    

    you can extract just the steps member with

    jq -r .steps
    

    To interpolate that into a sed statement, you'd need to escape any regex metacharacters in the result. A less intimidating and hopefully slightly less hacky solution would be to read static text from standard input:

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

    The struggle to educate practitioners to use structure-aware tools for structured data has reached epic heights and continues unabated. Before you decide to use the quick and dirty approach, at least make sure you understand the dangers (technical and mental).

    链接地址: http://www.djcxy.com/p/8278.html

    上一篇: Google数据源JSON无效?

    下一篇: sed替换变量包含换行符(保留它)