Question

I am trying to insert few lines before a specific line in an xml file. Though it's working but the formatting is not retained. Leading whitespaces are getting ignored. I know that we have to use IFS= and i also cross-checked it in the following link besides many others but to no avail. :(

Can anyone please point out the mistake i am committing here?

Preserving leading white space while reading>>writing a file line by line in bash

while read line
do
    pattern=keepDependencies
    input_file=/home/john/data_file
    file_to_change="${backup_dir}/"$line"/config.xml"

    while IFS= read -r insert_text
    do
        sed -i "/$pattern/i $insert_text" $file_to_change
    done < "$input_file"
done < days_to_keep_absent



Data File:

[john ~]$ cat data_file
  <logRotator>
        <daysToKeep>-1</daysToKeep>
        <numToKeep>5</numToKeep>
        <artifactDaysToKeep>-1</artifactDaysToKeep>
        <artifactNumToKeep>-1</artifactNumToKeep>
  </logRotator>



config.xml:

<?xml version='1.0' encoding='UTF-8'?>
<project>
  <actions/>
  <description>I&apos;ll clean all the temporary permissions</description>
  <keepDependencies>false</keepDependencies>
  <properties>
    <hudson.security.AuthorizationMatrixProperty>
    ...
    ...



Output:

<?xml version='1.0' encoding='UTF-8'?>
<project>
  <actions/>
  <description>I&apos;ll clean all the temporary permissions</description>
<logRotator>
<daysToKeep>-1</daysToKeep>
<numToKeep>5</numToKeep>
<artifactDaysToKeep>-1</artifactDaysToKeep>
<artifactNumToKeep>-1</artifactNumToKeep>
</logRotator>
  <keepDependencies>false</keepDependencies>
  <properties>
    <hudson.security.AuthorizationMatrixProperty>
    ...
    ...
Was it helpful?

Solution

It's not read which is giving you problems. It's sed.

The usual (and, as far as I know, the only Posix-compatible) way of issuing an i command is to follow it immediately with a backslash and a newline. The argument consists of the subsequent lines up to the first one not terminated with a backslash:

/pattern/i\
    This text is inserted\
So is this text.

GNU sed allows the inserted text to start on the same line as the i, following any whitespace. And that is why your whitespace is being deleted.

Try this:

while read line
do
  pattern=keepDependencies
  input_file=/home/john/data_file
  # Note: I fixed quoting in the following line.
  file_to_change="$backup_dir/$line/config.xml"

  while IFS= read -r insert_text
  do
    # Note: \\ is reduced to \ because it is inside a double-quoted string
    # The newline is inserted directly. So sed sees i\<newline><inserted text>
    sed -i "/$pattern/i\\
$insert_text" "$file_to_change"
  done < "$input_file"
done < days_to_keep_absent

I find that style a little hard to read, so I would usually do something like this:

ICMD='i\
'

# ...

sed -i "/$pattern/$ICMD$insert_text" "$file_to_change"

OTHER TIPS

This is a feature of read (and many other shell's function).

You could work around it: just prepend a char (ex: "|") to the file, and take that out when you output the line

I'll re-use your algorithm without checking it (you say it does do what you need it to, except for missing leading whitespaces) :

The while loop becomes:

sed -e 's/^/|/' < "${input_file}" > "${input_file}_modified"
while IFS= read -r insert_text
do
    sed -i "/$pattern/i $( echo "$insert_text" | sed -e 's/^|//' )" $file_to_change
done < "${input_file}_modified"

Hope this helps

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top