How to substitute a paragraph in file?

2020-05-03 11:40发布

问题:

I want to change more than a line of a file. It is a CSS file and I want to swap out a section to another.

This is a snippet from the file:

    /*** Debugging ***/
    draw-button-bounding-rects: false;
    draw-button-rects: false;
    debug-touch-points: false;
    draw-reactive-areas: false;
}

MImAbstractKeyAreaStyle.Landscape {
    /*** Label Setttings ***/
    label-margin-top: 0.6mm;
    label-margin-left-with-secondary: -1; /* not used, labels are centered horizontally */
    secondary-label-separation: 0;

    /*** Behaviour ***/
    touchpoint-horizontal-gravity: 32px;
    touchpoint-vertical-gravity: 20px;

    /*** Key Geometry ***/
    key-height-small: -1; /* unused */
    key-height-medium: 46px;
    key-height-large: 66px;
    key-height-x-large: 82px;
    key-height-xx-large: -1; /* unused */

    key-width-small-fixed: -1; /* unused */
    key-width-medium-fixed: 76px;
    key-width-large-fixed: 93px;
    key-width-x-large-fixed: 178px;
    key-width-xx-large-fixed: 244px;
    key-width-stretched-fixed: -1; /* unused */

    key-margin-left: 4px;
    key-margin-top: 0px;
    key-margin-right: 4px;
    key-margin-bottom: 12px;

    padding-left: 11px;
    padding-top: 8px;
    padding-right: 11px;
    padding-bottom: 8px;

    /*** Key Area Geometry ***/
    size: 854 -1;
}

MImAbstractKeyAreaStyle.Portrait {

If I use sed -n '/aStyle.Landscape {/,/}/p' it prints the correct paragraph but I want to substitute that with another. I have tried with sed '/aStyle.Landscape {/}/s/aStyle.Landscape {/something/' and similar but I am missing something.

回答1:

The sed syntax you show is not entirely accurate; if it worked, then you must have used:

sed -n '/aStyle.Landscape {/,/}/p'

to print the lines from 'aStyle.Landscape' to the closing brace.

If you want to replace that paragraph, then you can do:

sed '/aStyle.Landscape {/,/}/c\
MImAbstractKeyAreaStyle.Landscape {\
    /*** Label Setttings ***/\
    label-margin-top: 6.0mm;\
    label-margin-left-with-secondary: +1;\
    secondary-label-separation: 2;\
    ...\
}'

Note that each line in the replacement text except the last is followed by a backslash.

You might find it better to use a script file:

sed -f sed.script css.file

When I ran the script above, copied verbatim from this answer into a file 'xx', on the CSS fragment from the question (in 'xx.css') using sh xx < xx.css, the output I got was:

    /*** Debugging ***/
    draw-button-bounding-rects: false;
    draw-button-rects: false;
    debug-touch-points: false;
    draw-reactive-areas: false;
}

MImAbstractKeyAreaStyle.Landscape {
    /*** Label Setttings ***/
    label-margin-top: 6.0mm;
    label-margin-left-with-secondary: +1;
    secondary-label-separation: 2;
    ...
}

MImAbstractKeyAreaStyle.Portrait {

You said you got everything on one line...I wonder how you ran the script? If everything was 'on one line', I wonder if you do something like:

output=$(sed ... file.css)

followed by:

echo $output

This would flatten everything to one line (think of it as minimization). The shape of the CSS would be preserved if you wrote instead:

echo "$output"

This question shows how the 'flattening' problem arose. There were two levels of shell interpretation (the shell that runs the su command, and the shell that is run by the su command), which is enough to give anyone a headache. Doubling up the backslashes might be sufficient, but I'd create a script and run that.



回答2:

This might work for you to:

cat <<\EOF > new_para.txt
MImAbstractKeyAreaStyle.Landscape
    /*** Label Setttings ***
    label-margin-top: 6.0mm;
    label-margin-left-with-secondary: +1;
    secondary-label-separation: 2;
    ...
}
EOF
> MImAbstractKeyAreaStyle.Landscape
>     /*** Label Setttings ***
>     label-margin-top: 6.0mm;
>     label-margin-left-with-secondary: +1;
>     secondary-label-separation: 2;
>     ...
> }
sed -i -e '/aStyle.Landscape {/,/}/{/}/r new_para.txt' -e ';d}' file.css

If the replacement paragraph is of the same length and your using GNU sed, this would work to:

sed -i -e '/aStyle.Landscape {/,/}/{R new_para.txt' -e ';d}' file.css

N.B. The last method only works for a single replacement, unless each paragraph to be replaced (in order) is in the new_para.txt file. This does give the user a chance to tailor each replacement paragraph, a subtle but powerful difference.

EDIT:

To achieve the same result without an intermediate file:

cat <<\EOF | sed -i -e '/aStyle.Landscape {/,/}/{/}/r /dev/stdin ' -e ';d}' file.css
MImAbstractKeyAreaStyle.Landscape
    /*** Label Setttings ***
    label-margin-top: 6.0mm;
    label-margin-left-with-secondary: +1;
    secondary-label-separation: 2;
    ...
}
EOF