10

In a XML configuration file I need to add a line, in order to not to break the last closing tag. Is it possible to do it with SED ?

The number of line of the whole file can change from a server to another...

Edit : Some exemple of file I need to edit :

<configuration>

  <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
    <!-- encoders are assigned the type
         ch.qos.logback.classic.encoder.PatternLayoutEncoder by default -->
    <encoder>
      <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
    </encoder>
  </appender>

  <root level="debug">
    <appender-ref ref="STDOUT" />
  </root>
</configuration>

An other exemple:

  <?xml version="1.0" encoding="UTF-8"?>
  <configuration>

    <property name="DEV_HOME" value="c:/logs" />

    <appender name="FILE-AUDIT"
      class="ch.qos.logback.core.rolling.RollingFileAppender">
      <file>${DEV_HOME}/debug.log</file>
      <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
        <Pattern>
          %d{yyyy-MM-dd HH:mm:ss} - %msg%n
        </Pattern>
      </encoder>

      <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
        <!-- rollover daily -->
        <fileNamePattern>${DEV_HOME}/archived/debug.%d{yyyy-MM-dd}.%i.log
                          </fileNamePattern>
        <timeBasedFileNamingAndTriggeringPolicy
          class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
          <maxFileSize>10MB</maxFileSize>
        </timeBasedFileNamingAndTriggeringPolicy>
      </rollingPolicy>

    </appender>

    <logger name="com.mkyong.web" level="debug"
      additivity="false">
      <appender-ref ref="FILE-AUDIT" />
    </logger>

    <root level="error">
      <appender-ref ref="FILE-AUDIT" />
    </root>

    <logger name="com.mkyong.ext" level="debug"
      additivity="false">
      <appender-ref ref="FILE-AUDIT" />
    </logger>

      <logger name="com.mkyong.other" level="info"
      additivity="false">
      <appender-ref ref="FILE-AUDIT" />
    </logger>

      <logger name="com.mkyong.commons" level="debug"
      additivity="false">
      <appender-ref ref="FILE-AUDIT" />
    </logger>
  </configuration>
7
  • 2
    To manipulate XML files you should really use XML tools such as XMLStarlet... Commented Apr 6, 2017 at 9:31
  • @StephenKitt You're right but I need tools included with Ubuntu12 because I can't install new tools on the server. Commented Apr 6, 2017 at 9:39
  • 3
    What a mess... Could you perhaps post a very short input sample and the expected output ? Commented Apr 6, 2017 at 9:41
  • 1
    And yet you’re allowed to manipulate Log4J XML files directly on the server? O_O Commented Apr 6, 2017 at 9:51
  • 1
    Notice that any script that comes out of here may be considered a tool that needs to be tested and validated too. Just saying.
    – Kusalananda
    Commented Apr 6, 2017 at 9:55

2 Answers 2

19

To insert a line before the last ($) one:

$ cat test
one
two
three
four
five

$ sed '$i<hello>!' test
one
two
three
four
<hello>!
five

That's for GNU sed (and beware leading spaces or tabs are stripped). Portably (or with GNU sed, if you want to preserve the leading spaces or tabs in the inserted line), you'd need:

sed '$i\
<hello>!' test
1
  • For anyone who, like me, is trying to insert a leading tab with this solution and running into problems (perhaps because I'm using sed from busybox?) the following works: sed -e '$i \' -e $'\t'"scan_ssid=1" /tmp/connect.conf Commented Feb 2, 2022 at 20:04
3

Yes, sed can be told to act on only a specific line by writing the line number before the operation you tell it to perform. For example, to insert a line with the string foo after the 4th line of a file, you could do:

sed '4s/$/\nfoo/' file  # GNU sed and a few others
sed '4s/$/\
foo/' file # standardly/portably

To insert a line after the next to last line, I can think of two approaches:

  1. Count the number of lines first and then make the edit:

    sed "$(( $( wc -l < file) -2 ))s/$/\nfoo/" file
    
  2. Use tac:

    tac file | sed '2s/$/\nfoo/' | tac
    
5
  • As far as I understand I can't use the sed's -i option with tac? Commented Apr 6, 2017 at 9:42
  • @Fractaliste no, not with tac, but you can always do tac file | sed '2s/$/\nfoo/' | tac > newfile && mv newfile file
    – terdon
    Commented Apr 6, 2017 at 9:43
  • 1
    You just sed '$s/^/foo\n/' to insert before the last one. Commented Apr 6, 2017 at 10:04
  • @StéphaneChazelas yes, I know that now, after reading Kamaraj's answer, but I wasn't aware of that when I posted mine.
    – terdon
    Commented Apr 6, 2017 at 10:33
  • @StéphaneChazelas yes, but this answer is still useful when one needs to refer to a line BEFORE an address (for the sake of s or d commands) since sed has no concept of negative offset/block. One can use analogies from this example.
    – bloody
    Commented Mar 22, 2023 at 9:54

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .