0

My problem in here is I want to write the value for $i on a specific lines in the config.xml, see below structure of config.xml. Also I want all the lines to be one below another not in same line.

#!/bin/bash

NAME_ID=( User1 User2 User3 )
USER_CONF=/opt/test/config.xml

for i in "${NAME_ID[@]}"; do
      
  printf '<user><id>ID</id><name><%s/name></user>\n' "$i" >> "$EXTERNAL_USER_CONF"

done

config.xml structure below(I want to insert all three lines one below another where it says USER_TO_INSER_HERE but instead I get them in the end):

<company type="external">
    <enabled>true</enabled>
    <users type="allowed">
        USER_TO_INSERT_HERE
    </users>
</company>
        <domain><id>ID</id><name><User1/name></domain>
        <domain><id>ID</id><name><User2/name></domain>
        <domain><id>ID</id><name><User3/name></domain>

What I would expect to be the final result is:

<company type="external">
    <enabled>true</enabled>
    <users type="allowed">
        <domain><id>ID</id><name><User1/name></domain>
        <domain><id>ID</id><name><User2/name></domain>
        <domain><id>ID</id><name><User3/name></domain>
    </users>
</company>
miken32
  • 42,008
  • 16
  • 111
  • 154
Rado Ratko
  • 49
  • 5
  • 2
    `on a specific lines` which lines specifically? To modify XML files, use XML -aware tools, like `xmlstarlet`. Also `` and `` is invalid XML. – KamilCuk Mar 09 '21 at 21:40
  • thanks @KamilCuk just fixed your recommendations you were right I overlooked the xml as I am trying to focus on my bigger problem. – Rado Ratko Mar 09 '21 at 22:05

2 Answers2

1

The following code:

tmp=$(cat <<EOF
<company type="external">
    <enabled>true</enabled>
    <users type="allowed">
    </users>
</company>
EOF
)

for i in user1 user2 user3; do
      value=$(printf '<id>ID</id><name>%s</name>\n' "$i")
      tmp=$(xmlstarlet ed -s '/company/users' -t elem -n domain -v "$value" <<<"$tmp")
done

tmp=$(xmlstarlet unesc <<<"$tmp")
cat <<<"$tmp"

outputs on my pc with xml 1.6.1:

<?xml version="1.0"?>
<company type="external">
  <enabled>true</enabled>
  <users type="allowed">
    <domain><id>ID</id><name>user1</name></domain>
    <domain><id>ID</id><name>user2</name></domain>
    <domain><id>ID</id><name>user3</name></domain>
  </users>
</company>

it is based on How do I use xmlstarlet to append xml files with multiple sub node?

KamilCuk
  • 120,984
  • 8
  • 59
  • 111
  • There is only one flow in that implementation seems like the users are written in one line, I tried addind \n but did not work in xmlstarled. Do you know how can I new line after every: ID – Rado Ratko Mar 09 '21 at 22:28
  • 1
    `one flow` I think you meant one __flaw__. I get newlines after every ``. Instead of doing it manually, format it with a tool. Like literally with `xmlstarlet fo`. But I suggest to use a better language to work with XML. Like python. – KamilCuk Mar 10 '21 at 00:09
0

Using a pure bash shell solution, which will be excruciatingly/painfully slow on large set of data/files.

The file.xml and it's content.

<company type="external">
    <enabled>true</enabled>
    <users type="allowed">
    </users>
</company>

The script.

#!/usr/bin/env bash

user_conf=file.xml
name_id=(User{1..10})
line_to_insert_user_below='^([[:blank:]]+)<users="allowed">'

while IFS= read -r line; do
  if [[ $line =~ $line_to_insert_user_below ]]; then
    intended_ouput+=("$line")
    leading_space=${BASH_REMATCH[1]}
    leading_space+=$leading_space
    for i in "${name_id[@]}"; do
      intended_ouput+=(
        "$leading_space<domain><id>ID</id><name><$i</name></domain>"
      )
    done
    continue
  fi
  intended_ouput+=("$line")
done < "$user_conf"

printf '%s\n' "${intended_ouput[@]}" > "$user_conf"

The edited output of the file.xml

<company="external">
    <enabled>true</enabled>
    <users="allowed">
        <domain><id>ID</id><name><User1/name></domain>
        <domain><id>ID</id><name><User2/name></domain>
        <domain><id>ID</id><name><User3/name></domain>
        <domain><id>ID</id><name><User4/name></domain>
        <domain><id>ID</id><name><User5/name></domain>
        <domain><id>ID</id><name><User6/name></domain>
        <domain><id>ID</id><name><User7/name></domain>
        <domain><id>ID</id><name><User8/name></domain>
        <domain><id>ID</id><name><User9/name></domain>
        <domain><id>ID</id><name><User10/name></domain>
    </users>
</company>    

As mentioned on the other answer, use a tool that is xml aware or a language that has a library for parsing and editing xml files. This solution is just a last resort say if you don't have access to such tools and the files are not huge.

Jetchisel
  • 7,493
  • 2
  • 19
  • 18