用 sed 替换文件中的部分

用 sed 替换文件中的部分

我想替换 xorg 文件的一部分。这可以用 sed 完成吗?

原始部分,即替换““Screen”部分”和“EndSection”之间的所有内容...

Section "Screen"
    Identifier     "Screen0"
    Device         "Device0"
    Monitor        "Monitor0"
    DefaultDepth    24
    SubSection     "Display"
        Depth       24
    EndSubSection
EndSection

...替换为全新的内容(多行)。例如

Section "Screen"
    SomeSpecs   "somevalue"
    SomeOptions "somevalues"
EndSection

答案1

sed '/Section "Screen"/,/EndSection/s/\(Identifier.*\)Screen0/\1somethingelse/' xorg-file

如果要替换inline,需要-i在sed后面添加。

答案2

虽然可以使用sed(或多或少容易取决于 的实现sed)来完成,但使用perl会更合适:

file=xorg.conf
screen_to_replace=Screen0
new_section='    Identifier "somethingelse"
    Device ...
'

perl -0777 -spi -e '
  s{^\h*Section\h+"Screen"\h*\n\K.*?(?=^\h*EndSection\h*$)}{
    my $section = $&;
    if ($section =~ /^\h*Identifier\h+"\Q$screen_to_replace\E"\h*$/m) {
      $new_section;
    } else {
      $section;
    }
  }smeg' -- -screen_to_replace="$screen_to_replace" \
            -new_section="$new_section" \
         -- "$file"

或者-MEnglish对内置文档进行一些注释:

file=xorg.conf
screen_to_replace=Screen0
new_section='    Identifier "somethingelse"
    Device ...
'

perl -MEnglish -0777 -spi -e '
  s{
     ^             # beginning of a line
     \h*           # any amount of horizontal spacing
     Section       # literally
     \h+           # at least one horizontal space
     "Screen"      # literally
     \h*        
     \n            # a line delimiter
     \K            # Keep only what follows from what is matched
     .*?           # anything as little as possibly up until
     (?=           # looking ahead for:
       ^           # beginning of a line
       \h*         # any amount of horizontal spacing
       EndSection  # literally
       \h*         # any amount of horizontal spacing
       $           # the end of a line
     )
  }{
    my $section = $MATCH;
    if ($section =~ m{
      ^           # beginning of a line
      \h*         # any amount of horizontal spacing
      Identifier  # literally
      \h+         # at least one horizontal space
      "\Q$screen_to_replace\E" # "the_old_id", \Q...\E for it to
                               # be taken literally even if it contains
                               # regexp operators.
      \h*         # any amount of horizontal spacing
      $           # the end of a line
    }mx)
    {
      $new_section;
    } else {
      $section;
    }
  }sxmeg' -- -screen_to_replace="$screen_to_replace" \
             -new_section="$new_section" \
          -- "$file"

正如您提到的,出于某种原因您想要一行代码,我认为您不太关心可读性,那么:

perl -0777pi -e's{^\h*Section\h+"Screen"\h*\n\K.*?(?=^\h*EndSection\h*$)}{($s=$&)=~/^\h*Identifier\h+"Screen0"\h*$/m?qq(    Identifier "somethingelse"\n    Device ...\n):$s}smeg' xorg.conf

这里所有参数都是硬编码的。

答案3

首先看看如何sed 选择行

# print ('p') lines between line that contain 'Section' and line that contain 'EndSection'
sed -n '/Section/,/EndSection/ p' xorg.conf
# to same + line starts ('^') with these text
sed -n '/^Section/,/^EndSection/ p' xorg.conf
# to same + 'Section' line must contain 'Screen'
sed -n '/^Section.*Screen/,/^EndSection/ p' xorg.conf

定义我们的“选择线”

l1='^Section.*Screen'; l2='^EndSection'
# to same as last command (only for test)
sed -n "/$l1/,/$l2/ p" xorg.conf   # be careful, now use " (double quotes)

最后进行一些替换(在sed“语言”替换中s)。从此永远在$l1$l2行之间!

# replace 'Identifier' by 'BLA1'
sed "/$l1/,/$l2/ s/Identifier/BLA1/" xorg.conf
# replace whole line with 'Identifier' by 'BLA2'
sed "/$l1/,/$l2/ s/Identifier.*/BLA2/" xorg.conf
# and finally what do you want
sed "/$l1/,/$l2/ s/Identifier.*/Identifier \"somethingelse\"/" xorg.conf

相关内容