0

If I search file eg. file.xml for s_webdomain I will get:

        <hostname oa_var="s_webhost">hostname</hostname>
     <externURL oa_var="s_external_url">https://hostname:4450</externURL>
     <directory_index oa_var="s_directory_index">index.html</directory_index>
     <webentryhost oa_var="s_webentryhost">hostname.host</webentryhost>
     <webentrydomain oa_var="s_webentrydomain">services.uk</webentrydomain>
     <domain oa_var="s_webdomain">services.uk</domain>
     <server_ip_address oa_var="s_server_ip_address"/>
     <!-- Configuration files -->
     <!-- SSL Variables -->
     <url_protocol oa_var="s_url_protocol">http</url_protocol>
     <web_ssl_directory oa_var="s_web_ssl_directory">/u03/app/ENV/gs/inst/ENV_01-bsapp01/certs</web_ssl_directory>
     <local_url_protocol oa_var="s_local_url_protocol">http</local_url_protocol>

I want to replace services.uk no matter what it says to :

<domain oa_var="s_webdomain">SOME_DIFFERENT_TEXT</domain>

$ grep s_webdomain file.xml | awk -F '>' '{print $2}' | awk -F '<' '{print $1}'

services.uk

Any ideas about how to change services.uk to SOME_DIFFERENT_TEXT ? probably needs a sed command, but I'm not sure .

Thanks.

AUser
  • 3
  • 2
    Can you give us a more complete example of your file? Attempting to parse structured languages like XML or HTML with basic text parsing tools and regular expressions can work, but it is very fragile and bad practice. If you give us a fuller example of the file, we can help you do this using dedicated XML parsers. – terdon Oct 11 '22 at 15:35

3 Answers3

2

When dealing with a document in a structured document format, the best processing tool are the ones that are aware of that format.

The following uses the XML processing tool xmlstarlet to replace the value of all domain nodes that have an ou_var attribute with the value s_webdomain:

xmlstarlet edit \
    --update '//domain[@oa_var = "s_webdomain"]' \
    --value "SOME_DIFFERENT_TEXT" file

or, using short options,

xmlstarlet ed \
    -u '//domain[@oa_var = "s_webdomain"]' \
    -v "SOME_DIFFERENT_TEXT" file

The command uses an XPath query, //domain[@oa_var = "s_webdomain"], to address all the possible places in the input document that will be updated. Each matching entity will have its value updated to, in this case, the string SOME_DIFFERENT_TEXT.

The initial // in the Xpath pattern means that the domain node may be found anywhere. Usually, one knows the document's structure and would instead specify a more exact path to the node(s) that one intends to process.

You may add --inplace (-L) after edit to make the changes in the document "in-place".

To affect multiple nodes, for example, the webentrynode with an oa_var value of s_webentrydomain:

xmlstarlet edit \
    --update '//domain[@oa_var = "s_webdomain"]' \
    --value "SOME_DIFFERENT_TEXT" \
    --update '//webentrydomain[@oa_var = "s_webentrydomain"]' \
    --value "SOME_DIFFERENT_TEXT" file

To extract the value(s), you would use xmlstarlet select, like so:

xmlstarlet select \
    --template \
    --value-of '//domain[@oa_var = "s_webdomain"]' \
    -nl file

or, using short options,

xmlstarlet sel -t -v '//domain[@oa_var = "s_webdomain"]' -n file
Kusalananda
  • 333,661
1

You can just use awk by itself:

To test it:
awk '{sub(/s_webdomain\">services.uk/,"s_webdomain\">some_new_text"); print}' file.xml

and to write it inplace:
awk -i inplace '{sub(/s_webdomain\">services.uk/,"s_webdomain\">some_new_text"); print}' file.xml

Shōgun8
  • 711
  • I think this will change all occurrences of services.uk to SOME_NEW_TEXT. I only want to change it for a specific line in the code. Thanks for your reply. – AUser Oct 12 '22 at 07:00
  • The original command would have, so I updated it to address the one particular occurrence – Shōgun8 Oct 13 '22 at 19:11
0

With your Example Document having all the tags (& all the matching lines you want) on single lines , I would make this Simple Perl Command to change that text :

#
# perl -i.bak -p -e "s/(<.*>)(.*)(<.*>)/\${1}SOME_DIFFERENT_TEXT\${3}/ if /s_webdomain/" file.xml 
#
# diff file.xml file.xml.bak 
10c10
<      <domain oa_var="s_webdomain">SOME_DIFFERENT_TEXT</domain>
---
>      <domain oa_var="s_webdomain">services.uk</domain>
#

Simple Perl Command is making backup file with *.bak extention , & printing every line in the given text file , & using a regex to match the lines with s_webdomain , then substituting the central text with SOME_DIFFERENT_TEXT , to generate the output file.

Diff Command shows what has changed , by comparing updated contents in the text file with the original contents in the backup file.

Perl may already be installed & available. This Solution is very quick & It can be extended with tweaking.

Prem
  • 3,342
  • Thank you very much, this is perfect. – AUser Oct 12 '22 at 06:59
  • perl -i.bak -p -e "s/(<.>)(.)(<.>)/${1}/u03/app/jdk32/jre/lib/security/cacerts${3}/ if /s_ssl_truststore/" $THE_FILE - it doesn't like / it seems. I get Bareword found where operator expected at -e line 1, near "s/(<.>)(.)(<.>)/${1}/u03" syntax error at -e line 1, near "s/(<.>)(.)(<.*>)/${1}/u03" Execution of -e aborted due to compilation errors. Is there a way to avoid the / problem in perl ? Thanks again for your help. – AUser Oct 12 '22 at 16:27
  • 1
    @user2346372 and that's why using an XML-aware tool is more reliable – Chris Davies Oct 12 '22 at 23:02
  • I think you did not read that comment , OP is asking a new question , @roaima – Prem Oct 13 '22 at 04:37
  • What you have given may have a Simple Solution , but it is not good to ask new questions in comments & answer them via comments. I suggest you Post a new Question with what you want & what you are trying & what the Issue is. I think , we can give a Simple Solution to that Question. @user2346372 – Prem Oct 13 '22 at 04:43
  • In other words : OP has a new Problem , in a new Case , which is not because of xml-awareness , but because of wrong syntax. In xmlstarlet too , if we give "-- update" or "----value" or use "////" or "====" , we will get syntax issues. @roaima – Prem Oct 13 '22 at 05:35
  • not to worry, all sorted. Just needed to add \ before every /. Thanks all. – AUser Oct 13 '22 at 09:56
  • Oh , great to know that ! That was the Simple Solution which I had , but I could not put in the comments because (1) StackExchange "Policy" is like that , not to answer new questions in the comments (2) In the "Small Comment Area" , I can not easily explain which "/" to escape , & which "/" not to escape ! [[ You may want to know that putting "" in front of "/" has the terminology "ESCAPING" , in general ! ]] ++ [[ In the Answer , I mention "It can be extended with tweaking" & I was happy to know that you have already used this Answer to extend to your new Case ! ]] @user2346372 – Prem Oct 13 '22 at 10:54