Search code examples
xmllinuxparsingxmlstarlet

Parsing XML via a shell script


i'm using xmlstarlet into a shell script to parse an xml file untitled app.xml with this command, just to get the content of which is a string , and store it on "my_var" :

my_var=`xmlstarlet sel -t -m "//root/services/service[position=$i]" -v description -n /home/wissem/Bureau/app.xml`

then ,when trying to modify an other xml file untitled strings.xml with the output of the last command , using this command line :

find /root/AndroidStudioProjects/FacebookMenu/app/src/main/res/values/strings.xml -type f -exec  perl -pi -w -e 's/name=\"text_'$i'\".*\<\/string\>/name=\"text_'$i'\"\>'$my_var'\<\/string\>/g' {} \;

i get the following error :

Substitution replacement not terminated at -e line 1.

i tried to understand the problem by changing severally the string that i'm parsing into my variable , i noticed that the problem appears when i have a "space" on the string !

to explain more :for this_is_my_string : it works

for this is my string : i get the error.


Solution

  • Yeah, if $my_var contains spaces, the shell will break arguments in $my_var. This should work:

    -e "s;name=\"text_$i\".*</string>;name=\"text_$i\">$my_var</string>;g"
    

    The double quotes prevent your argument from being split. The double quotes you want to be part of your argument were already quoted with backslashes, which protects them. And $ variables are expanded when appearing in double quotes. I've also replaced s/../../g with s;...;...;g so that forward slashed don't need escaping. And I'm pretty sure there's no reason to escape the angle brackets.

    I've tested the above with this procedure:

    1. Create /tmp/testq.xml containing:

      <string name="text_100">Blah</string>
      
    2. Issue:

      i=100
      my_var="room service"
      
    3. Issue:

      find /tmp/ -name "testq.xml" -exec perl -p -e "s;name=\"text_$i\".*</string>;name=\"text_$i\">$my_var</string>;g" '{}' \;
      
    4. Result to stdout:

      <string name="text_100">room service</string>
      

    I don't use -i in the test above because I want to be able to rerun the test any number of times, but -i should not affect the validity of the -e expression.