Nested conditional search and in-place substituition











up vote
1
down vote

favorite












I'm an awk newbie. I have a file that looks like:



beans and celery  
beans and oatmeal
beans and beans
quinoa
<fo:external-graphic width="auto" height="auto" content-width="36pt" src="url(file:/C:/Users/xxx/images/tip.svg)"/>
<fo:external-graphic src="url(images/image1.png)" width="6.3in" height="auto" content-width="246px" content-height="322px"/>


I'm trying to perform a search and replace in-place for the "fo" tag. I want to capture the beginning of the tag, as well as the "src" parameter. Please note that the position of the src tag varies from line to line!



I've been able to get the fields I want using the following:



awk '/<fo:external-graphic.*/ {for (i=1; i<=NF; ++i) {if ($i ~ "src") print $1 " " $i}}' inventory.txt


How can I do an in-place substitution of this?
I also want to append a string to new contents of the line. I've tried:



awk '/<fo:external-graphic.*/ {for (i=1; i<=NF; ++i) {if ($i ~ "src") print $1 " " $i "misc stuff here"}}' inventory.txt


But it completely messes up the order of the resulting string, which I want to be of the form:



<fo:external-graphic src="url(images/image1.png)" misc stuff here


PS1:
Further clarification about what result I want:
The file contains strings like:



<fo:external-graphic width="auto" height="auto" content-width="36pt" src="url(file:/C:/Users/xxx/images/tip.svg)"/>
<fo:external-graphic src="url(images/image1.png)" width="6.3in" height="auto" content-width="246px" content-height="322px"/>


I want to process these in and get an output like:



<fo:external-graphic src="url(images/image1.png)" _completely new stuff here, till end of string_ />


for example:



<fo:external-graphic src="url(images/image1.png)" age="25" sex="M" />


I want the result to ALWAYS begin with:



<fo:external-graphic src="url(images/image1.png)"


then the extra stuff eg:



age="25" sex="M" />


No other part of the original string is needed in the final output.



PS2: Can I pack all this into a gsub? To the best of my knowledge, gsub only take two arguments. I've tried to make a complex expression, for the replace argument, but it keeps failing eg:



gawk '/<fo:external-graphic.*/ {for (i=1; i<=NF; ++i) {if ($i ~ "src") gsub($0, "boy band"); {print}}}' inventory.txt > testres


PS3: This is just a newbie observation, maybe I'm wrong. Consider a file with the following contents:



Donald Trump
Donald Duck
George Bush
Steve Austin


The regexp to search for all lines that begin with Donald is:



/^Donald/


If I want to replace all occurrences of "Donald" with "Barrack", I could do the following:



gawk -i inplace '{ gsub(/^Donald/, "Barrack"); { print } }' FILENAME


If I want to completely change all lines that contain "Donald" I would do:



gawk -i inplace '{ gsub(/^Donald.*/, "Barrack"); { print } }' FILENAME


gawk and gsub appear to only replace the span or whatever part of the string matches the given regexp. Thus if I want to completely change a whole line, my regexp should span the whole of that line.



PS4: Just to clear any ambiguities about the solution I expect. Given the following file:



<fo:external-graphic width="auto" height="auto" content-width="36pt" src="url(file:/C:/Users/xxx/images/tip.svg)"/>
<fo:external-graphic width="6.3in" height="auto" src="url(images/image1.png)" content-width="246px" content-height="322px"/>
<fo:external-graphic src="url(images/image1.png)" width="6.3in" content-width="246px" content-height="322px"/>


I'm looking for an awk/gawk solution that will replace this file with:



<fo:external-graphic src="url(file:/C:/Users/xxx/images/tip.svg)" age="25" sex="M" />
<fo:external-graphic src="url(images/image1.png)" age="25" sex="M"/>
<fo:external-graphic src="url(images/image1.png)" age="25" sex="M"/>


The target file must be changed.










share|improve this question
























  • @Inian It doesn't appear to update the file. Please see the my updated question to see the form I expect for the final answer!
    – user1801060
    Nov 22 at 9:49










  • @RavinderSingh13 Please see the latest update to my question! If you have any doubts, let me know. Thanks
    – user1801060
    Nov 22 at 9:59










  • @Inian Please see the latest update to my question! If you have any doubts, let me know. Thanks
    – user1801060
    Nov 22 at 10:00










  • My last update should fix your problem
    – Inian
    Nov 22 at 16:43















up vote
1
down vote

favorite












I'm an awk newbie. I have a file that looks like:



beans and celery  
beans and oatmeal
beans and beans
quinoa
<fo:external-graphic width="auto" height="auto" content-width="36pt" src="url(file:/C:/Users/xxx/images/tip.svg)"/>
<fo:external-graphic src="url(images/image1.png)" width="6.3in" height="auto" content-width="246px" content-height="322px"/>


I'm trying to perform a search and replace in-place for the "fo" tag. I want to capture the beginning of the tag, as well as the "src" parameter. Please note that the position of the src tag varies from line to line!



I've been able to get the fields I want using the following:



awk '/<fo:external-graphic.*/ {for (i=1; i<=NF; ++i) {if ($i ~ "src") print $1 " " $i}}' inventory.txt


How can I do an in-place substitution of this?
I also want to append a string to new contents of the line. I've tried:



awk '/<fo:external-graphic.*/ {for (i=1; i<=NF; ++i) {if ($i ~ "src") print $1 " " $i "misc stuff here"}}' inventory.txt


But it completely messes up the order of the resulting string, which I want to be of the form:



<fo:external-graphic src="url(images/image1.png)" misc stuff here


PS1:
Further clarification about what result I want:
The file contains strings like:



<fo:external-graphic width="auto" height="auto" content-width="36pt" src="url(file:/C:/Users/xxx/images/tip.svg)"/>
<fo:external-graphic src="url(images/image1.png)" width="6.3in" height="auto" content-width="246px" content-height="322px"/>


I want to process these in and get an output like:



<fo:external-graphic src="url(images/image1.png)" _completely new stuff here, till end of string_ />


for example:



<fo:external-graphic src="url(images/image1.png)" age="25" sex="M" />


I want the result to ALWAYS begin with:



<fo:external-graphic src="url(images/image1.png)"


then the extra stuff eg:



age="25" sex="M" />


No other part of the original string is needed in the final output.



PS2: Can I pack all this into a gsub? To the best of my knowledge, gsub only take two arguments. I've tried to make a complex expression, for the replace argument, but it keeps failing eg:



gawk '/<fo:external-graphic.*/ {for (i=1; i<=NF; ++i) {if ($i ~ "src") gsub($0, "boy band"); {print}}}' inventory.txt > testres


PS3: This is just a newbie observation, maybe I'm wrong. Consider a file with the following contents:



Donald Trump
Donald Duck
George Bush
Steve Austin


The regexp to search for all lines that begin with Donald is:



/^Donald/


If I want to replace all occurrences of "Donald" with "Barrack", I could do the following:



gawk -i inplace '{ gsub(/^Donald/, "Barrack"); { print } }' FILENAME


If I want to completely change all lines that contain "Donald" I would do:



gawk -i inplace '{ gsub(/^Donald.*/, "Barrack"); { print } }' FILENAME


gawk and gsub appear to only replace the span or whatever part of the string matches the given regexp. Thus if I want to completely change a whole line, my regexp should span the whole of that line.



PS4: Just to clear any ambiguities about the solution I expect. Given the following file:



<fo:external-graphic width="auto" height="auto" content-width="36pt" src="url(file:/C:/Users/xxx/images/tip.svg)"/>
<fo:external-graphic width="6.3in" height="auto" src="url(images/image1.png)" content-width="246px" content-height="322px"/>
<fo:external-graphic src="url(images/image1.png)" width="6.3in" content-width="246px" content-height="322px"/>


I'm looking for an awk/gawk solution that will replace this file with:



<fo:external-graphic src="url(file:/C:/Users/xxx/images/tip.svg)" age="25" sex="M" />
<fo:external-graphic src="url(images/image1.png)" age="25" sex="M"/>
<fo:external-graphic src="url(images/image1.png)" age="25" sex="M"/>


The target file must be changed.










share|improve this question
























  • @Inian It doesn't appear to update the file. Please see the my updated question to see the form I expect for the final answer!
    – user1801060
    Nov 22 at 9:49










  • @RavinderSingh13 Please see the latest update to my question! If you have any doubts, let me know. Thanks
    – user1801060
    Nov 22 at 9:59










  • @Inian Please see the latest update to my question! If you have any doubts, let me know. Thanks
    – user1801060
    Nov 22 at 10:00










  • My last update should fix your problem
    – Inian
    Nov 22 at 16:43













up vote
1
down vote

favorite









up vote
1
down vote

favorite











I'm an awk newbie. I have a file that looks like:



beans and celery  
beans and oatmeal
beans and beans
quinoa
<fo:external-graphic width="auto" height="auto" content-width="36pt" src="url(file:/C:/Users/xxx/images/tip.svg)"/>
<fo:external-graphic src="url(images/image1.png)" width="6.3in" height="auto" content-width="246px" content-height="322px"/>


I'm trying to perform a search and replace in-place for the "fo" tag. I want to capture the beginning of the tag, as well as the "src" parameter. Please note that the position of the src tag varies from line to line!



I've been able to get the fields I want using the following:



awk '/<fo:external-graphic.*/ {for (i=1; i<=NF; ++i) {if ($i ~ "src") print $1 " " $i}}' inventory.txt


How can I do an in-place substitution of this?
I also want to append a string to new contents of the line. I've tried:



awk '/<fo:external-graphic.*/ {for (i=1; i<=NF; ++i) {if ($i ~ "src") print $1 " " $i "misc stuff here"}}' inventory.txt


But it completely messes up the order of the resulting string, which I want to be of the form:



<fo:external-graphic src="url(images/image1.png)" misc stuff here


PS1:
Further clarification about what result I want:
The file contains strings like:



<fo:external-graphic width="auto" height="auto" content-width="36pt" src="url(file:/C:/Users/xxx/images/tip.svg)"/>
<fo:external-graphic src="url(images/image1.png)" width="6.3in" height="auto" content-width="246px" content-height="322px"/>


I want to process these in and get an output like:



<fo:external-graphic src="url(images/image1.png)" _completely new stuff here, till end of string_ />


for example:



<fo:external-graphic src="url(images/image1.png)" age="25" sex="M" />


I want the result to ALWAYS begin with:



<fo:external-graphic src="url(images/image1.png)"


then the extra stuff eg:



age="25" sex="M" />


No other part of the original string is needed in the final output.



PS2: Can I pack all this into a gsub? To the best of my knowledge, gsub only take two arguments. I've tried to make a complex expression, for the replace argument, but it keeps failing eg:



gawk '/<fo:external-graphic.*/ {for (i=1; i<=NF; ++i) {if ($i ~ "src") gsub($0, "boy band"); {print}}}' inventory.txt > testres


PS3: This is just a newbie observation, maybe I'm wrong. Consider a file with the following contents:



Donald Trump
Donald Duck
George Bush
Steve Austin


The regexp to search for all lines that begin with Donald is:



/^Donald/


If I want to replace all occurrences of "Donald" with "Barrack", I could do the following:



gawk -i inplace '{ gsub(/^Donald/, "Barrack"); { print } }' FILENAME


If I want to completely change all lines that contain "Donald" I would do:



gawk -i inplace '{ gsub(/^Donald.*/, "Barrack"); { print } }' FILENAME


gawk and gsub appear to only replace the span or whatever part of the string matches the given regexp. Thus if I want to completely change a whole line, my regexp should span the whole of that line.



PS4: Just to clear any ambiguities about the solution I expect. Given the following file:



<fo:external-graphic width="auto" height="auto" content-width="36pt" src="url(file:/C:/Users/xxx/images/tip.svg)"/>
<fo:external-graphic width="6.3in" height="auto" src="url(images/image1.png)" content-width="246px" content-height="322px"/>
<fo:external-graphic src="url(images/image1.png)" width="6.3in" content-width="246px" content-height="322px"/>


I'm looking for an awk/gawk solution that will replace this file with:



<fo:external-graphic src="url(file:/C:/Users/xxx/images/tip.svg)" age="25" sex="M" />
<fo:external-graphic src="url(images/image1.png)" age="25" sex="M"/>
<fo:external-graphic src="url(images/image1.png)" age="25" sex="M"/>


The target file must be changed.










share|improve this question















I'm an awk newbie. I have a file that looks like:



beans and celery  
beans and oatmeal
beans and beans
quinoa
<fo:external-graphic width="auto" height="auto" content-width="36pt" src="url(file:/C:/Users/xxx/images/tip.svg)"/>
<fo:external-graphic src="url(images/image1.png)" width="6.3in" height="auto" content-width="246px" content-height="322px"/>


I'm trying to perform a search and replace in-place for the "fo" tag. I want to capture the beginning of the tag, as well as the "src" parameter. Please note that the position of the src tag varies from line to line!



I've been able to get the fields I want using the following:



awk '/<fo:external-graphic.*/ {for (i=1; i<=NF; ++i) {if ($i ~ "src") print $1 " " $i}}' inventory.txt


How can I do an in-place substitution of this?
I also want to append a string to new contents of the line. I've tried:



awk '/<fo:external-graphic.*/ {for (i=1; i<=NF; ++i) {if ($i ~ "src") print $1 " " $i "misc stuff here"}}' inventory.txt


But it completely messes up the order of the resulting string, which I want to be of the form:



<fo:external-graphic src="url(images/image1.png)" misc stuff here


PS1:
Further clarification about what result I want:
The file contains strings like:



<fo:external-graphic width="auto" height="auto" content-width="36pt" src="url(file:/C:/Users/xxx/images/tip.svg)"/>
<fo:external-graphic src="url(images/image1.png)" width="6.3in" height="auto" content-width="246px" content-height="322px"/>


I want to process these in and get an output like:



<fo:external-graphic src="url(images/image1.png)" _completely new stuff here, till end of string_ />


for example:



<fo:external-graphic src="url(images/image1.png)" age="25" sex="M" />


I want the result to ALWAYS begin with:



<fo:external-graphic src="url(images/image1.png)"


then the extra stuff eg:



age="25" sex="M" />


No other part of the original string is needed in the final output.



PS2: Can I pack all this into a gsub? To the best of my knowledge, gsub only take two arguments. I've tried to make a complex expression, for the replace argument, but it keeps failing eg:



gawk '/<fo:external-graphic.*/ {for (i=1; i<=NF; ++i) {if ($i ~ "src") gsub($0, "boy band"); {print}}}' inventory.txt > testres


PS3: This is just a newbie observation, maybe I'm wrong. Consider a file with the following contents:



Donald Trump
Donald Duck
George Bush
Steve Austin


The regexp to search for all lines that begin with Donald is:



/^Donald/


If I want to replace all occurrences of "Donald" with "Barrack", I could do the following:



gawk -i inplace '{ gsub(/^Donald/, "Barrack"); { print } }' FILENAME


If I want to completely change all lines that contain "Donald" I would do:



gawk -i inplace '{ gsub(/^Donald.*/, "Barrack"); { print } }' FILENAME


gawk and gsub appear to only replace the span or whatever part of the string matches the given regexp. Thus if I want to completely change a whole line, my regexp should span the whole of that line.



PS4: Just to clear any ambiguities about the solution I expect. Given the following file:



<fo:external-graphic width="auto" height="auto" content-width="36pt" src="url(file:/C:/Users/xxx/images/tip.svg)"/>
<fo:external-graphic width="6.3in" height="auto" src="url(images/image1.png)" content-width="246px" content-height="322px"/>
<fo:external-graphic src="url(images/image1.png)" width="6.3in" content-width="246px" content-height="322px"/>


I'm looking for an awk/gawk solution that will replace this file with:



<fo:external-graphic src="url(file:/C:/Users/xxx/images/tip.svg)" age="25" sex="M" />
<fo:external-graphic src="url(images/image1.png)" age="25" sex="M"/>
<fo:external-graphic src="url(images/image1.png)" age="25" sex="M"/>


The target file must be changed.







awk






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Nov 22 at 13:13

























asked Nov 22 at 8:51









user1801060

1,29221835




1,29221835












  • @Inian It doesn't appear to update the file. Please see the my updated question to see the form I expect for the final answer!
    – user1801060
    Nov 22 at 9:49










  • @RavinderSingh13 Please see the latest update to my question! If you have any doubts, let me know. Thanks
    – user1801060
    Nov 22 at 9:59










  • @Inian Please see the latest update to my question! If you have any doubts, let me know. Thanks
    – user1801060
    Nov 22 at 10:00










  • My last update should fix your problem
    – Inian
    Nov 22 at 16:43


















  • @Inian It doesn't appear to update the file. Please see the my updated question to see the form I expect for the final answer!
    – user1801060
    Nov 22 at 9:49










  • @RavinderSingh13 Please see the latest update to my question! If you have any doubts, let me know. Thanks
    – user1801060
    Nov 22 at 9:59










  • @Inian Please see the latest update to my question! If you have any doubts, let me know. Thanks
    – user1801060
    Nov 22 at 10:00










  • My last update should fix your problem
    – Inian
    Nov 22 at 16:43
















@Inian It doesn't appear to update the file. Please see the my updated question to see the form I expect for the final answer!
– user1801060
Nov 22 at 9:49




@Inian It doesn't appear to update the file. Please see the my updated question to see the form I expect for the final answer!
– user1801060
Nov 22 at 9:49












@RavinderSingh13 Please see the latest update to my question! If you have any doubts, let me know. Thanks
– user1801060
Nov 22 at 9:59




@RavinderSingh13 Please see the latest update to my question! If you have any doubts, let me know. Thanks
– user1801060
Nov 22 at 9:59












@Inian Please see the latest update to my question! If you have any doubts, let me know. Thanks
– user1801060
Nov 22 at 10:00




@Inian Please see the latest update to my question! If you have any doubts, let me know. Thanks
– user1801060
Nov 22 at 10:00












My last update should fix your problem
– Inian
Nov 22 at 16:43




My last update should fix your problem
– Inian
Nov 22 at 16:43












2 Answers
2






active

oldest

votes

















up vote
2
down vote













Your attempt is right, but assuming your intention is add only on the word starting with src i.e. on $i, apply the action only for that field, and keep the other fields as-is



awk '/<fo:external-graphic.*/ {for (i=1; i<=NF; ++i) {if ($i ~ "src") $i = $i " misc stuff here"}}1' inventory.txt


The part $i = $i " misc stuff here" does action of appending the string only on the fields matching your regex condition. Notice the removal of print and appending of {..}1 at the end. What that basically means is re-construct the whole line based on the modifications done inside {..}. Since we are modifying only certain fields, the other ones are kept intact.



If you want to re-write the entire field starting with src and append some string, use a proper regex match with gsub() and append string after the matched text denoted by &



awk '/<fo:external-graphic.*/ {for (i=1; i<=NF; ++i) { if ($i ~ "src") gsub(/src="url([^"]*)"/, "& new string", $i ) }}1' inventory.txt


From OP's most recent edit, it seems OP just wants the src field modified with new string to be appended at the end. The rest of the fields can be ignored it seems. Using match() on GNU awk has an added advantage of adding a third parameter to store the captured groups as



awk -v newstr="age="25" sex="M"" 'match($0, /^(<fo:external-graphic).*(src="url([^"]*)").*(/>)$/, arr){ print arr[1]" "arr[2]" "newstr""arr[4]  }' file


Note that GNU awk did not have in-place modifications up until 4.1.2, on which you can just do



gawk -i inplace '{...}' inventory.txt


For versions earlier to that, use a temporary file



awk '{...}' inventory.txt > tmpfile && mv tmpfile inventory.txt


Or if you moreutils installed, use sponge to slurp the output from the first command and re-create the file back with the latest.



awk '{...}' inventory.txt | sponge inventory.txt




From your sample text on the question, one can't recognize if its some markup language of sorts (XML, HTML). If its a proper syntax aware language, then you should use a parser that knows that grammar.






share|improve this answer






























    up vote
    1
    down vote













    EDIT3: Adding one more code here as per OP's new edit.



    awk  '
    / width.*content-width.*src/{
    sub(/ width.*content-width.*src/," src")
    sub(//>$/," age="25" sex="M"&")
    }
    /src.*width/{
    match($0,/src[^)]*/)
    val=substr($0,RSTART,RLENGTH+2)
    sub(/src.*/,"")
    $0=$0 OFS val OFS "age="25" sex="M"/>"
    }
    1
    ' Input_file






    EDIT2: For changing complete line with respect to OP's PS3 could you please try following.



    awk '/^Donald/{$0="new_line_value"} 1'  Input_file
    new_line_value
    new_line_value
    George Bush
    Steve Austin






    EDIT: Since OP has changed expected output so adding solution as per that output now too.



    awk '/^<fo:external-graphic src=.*/ && match($0,/src=.*)"/){$0=substr($0,1,RSTART+RLENGTH) " new_value_bla_bla_here.. />"} 1' Input_file






    Could you please try following(haven't tested it thoroughly since your expected output is not clear).



    awk '
    /^<fo:/ && match($0,/src=.*>/){
    $0=substr($0,1,RSTART-1) OFS "new_value_here.." OFS substr($0,RSTART+RLENGTH+1)
    }
    1
    ' Input_file


    In this code checking a line which starts from <fo: string and then trying to catch string from src= till / by match and replacing that captured text with new string here.



    In case you want to save output into Input_file itself then append > temp_file && mv temp_file Input_file in above code too.






    share|improve this answer























    • The second line is ok. The first line prints out: <fo:external-graphic width="auto" height="auto" content-width="36pt" src="url(file:/C:/Users/xxx/images/tip.svg)"/ new_value_bla_bla_here.. />. Please feel free to test your solution against the file I provided at the beginning of my question
      – user1801060
      Nov 22 at 10:35












    • @user1801060, check now and let me know then? I was not checking condition for string ^<fo:external-graphic src= check now once?
      – RavinderSingh13
      Nov 22 at 10:54










    • Perhaps the mistake is mine. Here's a screenshot of my result: imgur.com/aENVTyD
      – user1801060
      Nov 22 at 11:41










    • @user1801060, is it like all src you want to match or any specific string you want it to do?
      – RavinderSingh13
      Nov 22 at 11:59






    • 1




      Great effort! The first one didn't work, the last two worked. I believe getting a regexp to work for all variants is the problem. I'll have a look at it tomorrow.
      – user1801060
      Nov 23 at 18:56











    Your Answer






    StackExchange.ifUsing("editor", function () {
    StackExchange.using("externalEditor", function () {
    StackExchange.using("snippets", function () {
    StackExchange.snippets.init();
    });
    });
    }, "code-snippets");

    StackExchange.ready(function() {
    var channelOptions = {
    tags: "".split(" "),
    id: "1"
    };
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function() {
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled) {
    StackExchange.using("snippets", function() {
    createEditor();
    });
    }
    else {
    createEditor();
    }
    });

    function createEditor() {
    StackExchange.prepareEditor({
    heartbeatType: 'answer',
    convertImagesToLinks: true,
    noModals: true,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: 10,
    bindNavPrevention: true,
    postfix: "",
    imageUploader: {
    brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
    contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
    allowUrls: true
    },
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    });


    }
    });














    draft saved

    draft discarded


















    StackExchange.ready(
    function () {
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53427025%2fnested-conditional-search-and-in-place-substituition%23new-answer', 'question_page');
    }
    );

    Post as a guest















    Required, but never shown

























    2 Answers
    2






    active

    oldest

    votes








    2 Answers
    2






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes








    up vote
    2
    down vote













    Your attempt is right, but assuming your intention is add only on the word starting with src i.e. on $i, apply the action only for that field, and keep the other fields as-is



    awk '/<fo:external-graphic.*/ {for (i=1; i<=NF; ++i) {if ($i ~ "src") $i = $i " misc stuff here"}}1' inventory.txt


    The part $i = $i " misc stuff here" does action of appending the string only on the fields matching your regex condition. Notice the removal of print and appending of {..}1 at the end. What that basically means is re-construct the whole line based on the modifications done inside {..}. Since we are modifying only certain fields, the other ones are kept intact.



    If you want to re-write the entire field starting with src and append some string, use a proper regex match with gsub() and append string after the matched text denoted by &



    awk '/<fo:external-graphic.*/ {for (i=1; i<=NF; ++i) { if ($i ~ "src") gsub(/src="url([^"]*)"/, "& new string", $i ) }}1' inventory.txt


    From OP's most recent edit, it seems OP just wants the src field modified with new string to be appended at the end. The rest of the fields can be ignored it seems. Using match() on GNU awk has an added advantage of adding a third parameter to store the captured groups as



    awk -v newstr="age="25" sex="M"" 'match($0, /^(<fo:external-graphic).*(src="url([^"]*)").*(/>)$/, arr){ print arr[1]" "arr[2]" "newstr""arr[4]  }' file


    Note that GNU awk did not have in-place modifications up until 4.1.2, on which you can just do



    gawk -i inplace '{...}' inventory.txt


    For versions earlier to that, use a temporary file



    awk '{...}' inventory.txt > tmpfile && mv tmpfile inventory.txt


    Or if you moreutils installed, use sponge to slurp the output from the first command and re-create the file back with the latest.



    awk '{...}' inventory.txt | sponge inventory.txt




    From your sample text on the question, one can't recognize if its some markup language of sorts (XML, HTML). If its a proper syntax aware language, then you should use a parser that knows that grammar.






    share|improve this answer



























      up vote
      2
      down vote













      Your attempt is right, but assuming your intention is add only on the word starting with src i.e. on $i, apply the action only for that field, and keep the other fields as-is



      awk '/<fo:external-graphic.*/ {for (i=1; i<=NF; ++i) {if ($i ~ "src") $i = $i " misc stuff here"}}1' inventory.txt


      The part $i = $i " misc stuff here" does action of appending the string only on the fields matching your regex condition. Notice the removal of print and appending of {..}1 at the end. What that basically means is re-construct the whole line based on the modifications done inside {..}. Since we are modifying only certain fields, the other ones are kept intact.



      If you want to re-write the entire field starting with src and append some string, use a proper regex match with gsub() and append string after the matched text denoted by &



      awk '/<fo:external-graphic.*/ {for (i=1; i<=NF; ++i) { if ($i ~ "src") gsub(/src="url([^"]*)"/, "& new string", $i ) }}1' inventory.txt


      From OP's most recent edit, it seems OP just wants the src field modified with new string to be appended at the end. The rest of the fields can be ignored it seems. Using match() on GNU awk has an added advantage of adding a third parameter to store the captured groups as



      awk -v newstr="age="25" sex="M"" 'match($0, /^(<fo:external-graphic).*(src="url([^"]*)").*(/>)$/, arr){ print arr[1]" "arr[2]" "newstr""arr[4]  }' file


      Note that GNU awk did not have in-place modifications up until 4.1.2, on which you can just do



      gawk -i inplace '{...}' inventory.txt


      For versions earlier to that, use a temporary file



      awk '{...}' inventory.txt > tmpfile && mv tmpfile inventory.txt


      Or if you moreutils installed, use sponge to slurp the output from the first command and re-create the file back with the latest.



      awk '{...}' inventory.txt | sponge inventory.txt




      From your sample text on the question, one can't recognize if its some markup language of sorts (XML, HTML). If its a proper syntax aware language, then you should use a parser that knows that grammar.






      share|improve this answer

























        up vote
        2
        down vote










        up vote
        2
        down vote









        Your attempt is right, but assuming your intention is add only on the word starting with src i.e. on $i, apply the action only for that field, and keep the other fields as-is



        awk '/<fo:external-graphic.*/ {for (i=1; i<=NF; ++i) {if ($i ~ "src") $i = $i " misc stuff here"}}1' inventory.txt


        The part $i = $i " misc stuff here" does action of appending the string only on the fields matching your regex condition. Notice the removal of print and appending of {..}1 at the end. What that basically means is re-construct the whole line based on the modifications done inside {..}. Since we are modifying only certain fields, the other ones are kept intact.



        If you want to re-write the entire field starting with src and append some string, use a proper regex match with gsub() and append string after the matched text denoted by &



        awk '/<fo:external-graphic.*/ {for (i=1; i<=NF; ++i) { if ($i ~ "src") gsub(/src="url([^"]*)"/, "& new string", $i ) }}1' inventory.txt


        From OP's most recent edit, it seems OP just wants the src field modified with new string to be appended at the end. The rest of the fields can be ignored it seems. Using match() on GNU awk has an added advantage of adding a third parameter to store the captured groups as



        awk -v newstr="age="25" sex="M"" 'match($0, /^(<fo:external-graphic).*(src="url([^"]*)").*(/>)$/, arr){ print arr[1]" "arr[2]" "newstr""arr[4]  }' file


        Note that GNU awk did not have in-place modifications up until 4.1.2, on which you can just do



        gawk -i inplace '{...}' inventory.txt


        For versions earlier to that, use a temporary file



        awk '{...}' inventory.txt > tmpfile && mv tmpfile inventory.txt


        Or if you moreutils installed, use sponge to slurp the output from the first command and re-create the file back with the latest.



        awk '{...}' inventory.txt | sponge inventory.txt




        From your sample text on the question, one can't recognize if its some markup language of sorts (XML, HTML). If its a proper syntax aware language, then you should use a parser that knows that grammar.






        share|improve this answer














        Your attempt is right, but assuming your intention is add only on the word starting with src i.e. on $i, apply the action only for that field, and keep the other fields as-is



        awk '/<fo:external-graphic.*/ {for (i=1; i<=NF; ++i) {if ($i ~ "src") $i = $i " misc stuff here"}}1' inventory.txt


        The part $i = $i " misc stuff here" does action of appending the string only on the fields matching your regex condition. Notice the removal of print and appending of {..}1 at the end. What that basically means is re-construct the whole line based on the modifications done inside {..}. Since we are modifying only certain fields, the other ones are kept intact.



        If you want to re-write the entire field starting with src and append some string, use a proper regex match with gsub() and append string after the matched text denoted by &



        awk '/<fo:external-graphic.*/ {for (i=1; i<=NF; ++i) { if ($i ~ "src") gsub(/src="url([^"]*)"/, "& new string", $i ) }}1' inventory.txt


        From OP's most recent edit, it seems OP just wants the src field modified with new string to be appended at the end. The rest of the fields can be ignored it seems. Using match() on GNU awk has an added advantage of adding a third parameter to store the captured groups as



        awk -v newstr="age="25" sex="M"" 'match($0, /^(<fo:external-graphic).*(src="url([^"]*)").*(/>)$/, arr){ print arr[1]" "arr[2]" "newstr""arr[4]  }' file


        Note that GNU awk did not have in-place modifications up until 4.1.2, on which you can just do



        gawk -i inplace '{...}' inventory.txt


        For versions earlier to that, use a temporary file



        awk '{...}' inventory.txt > tmpfile && mv tmpfile inventory.txt


        Or if you moreutils installed, use sponge to slurp the output from the first command and re-create the file back with the latest.



        awk '{...}' inventory.txt | sponge inventory.txt




        From your sample text on the question, one can't recognize if its some markup language of sorts (XML, HTML). If its a proper syntax aware language, then you should use a parser that knows that grammar.







        share|improve this answer














        share|improve this answer



        share|improve this answer








        edited Nov 22 at 16:54

























        answered Nov 22 at 8:56









        Inian

        38k63669




        38k63669
























            up vote
            1
            down vote













            EDIT3: Adding one more code here as per OP's new edit.



            awk  '
            / width.*content-width.*src/{
            sub(/ width.*content-width.*src/," src")
            sub(//>$/," age="25" sex="M"&")
            }
            /src.*width/{
            match($0,/src[^)]*/)
            val=substr($0,RSTART,RLENGTH+2)
            sub(/src.*/,"")
            $0=$0 OFS val OFS "age="25" sex="M"/>"
            }
            1
            ' Input_file






            EDIT2: For changing complete line with respect to OP's PS3 could you please try following.



            awk '/^Donald/{$0="new_line_value"} 1'  Input_file
            new_line_value
            new_line_value
            George Bush
            Steve Austin






            EDIT: Since OP has changed expected output so adding solution as per that output now too.



            awk '/^<fo:external-graphic src=.*/ && match($0,/src=.*)"/){$0=substr($0,1,RSTART+RLENGTH) " new_value_bla_bla_here.. />"} 1' Input_file






            Could you please try following(haven't tested it thoroughly since your expected output is not clear).



            awk '
            /^<fo:/ && match($0,/src=.*>/){
            $0=substr($0,1,RSTART-1) OFS "new_value_here.." OFS substr($0,RSTART+RLENGTH+1)
            }
            1
            ' Input_file


            In this code checking a line which starts from <fo: string and then trying to catch string from src= till / by match and replacing that captured text with new string here.



            In case you want to save output into Input_file itself then append > temp_file && mv temp_file Input_file in above code too.






            share|improve this answer























            • The second line is ok. The first line prints out: <fo:external-graphic width="auto" height="auto" content-width="36pt" src="url(file:/C:/Users/xxx/images/tip.svg)"/ new_value_bla_bla_here.. />. Please feel free to test your solution against the file I provided at the beginning of my question
              – user1801060
              Nov 22 at 10:35












            • @user1801060, check now and let me know then? I was not checking condition for string ^<fo:external-graphic src= check now once?
              – RavinderSingh13
              Nov 22 at 10:54










            • Perhaps the mistake is mine. Here's a screenshot of my result: imgur.com/aENVTyD
              – user1801060
              Nov 22 at 11:41










            • @user1801060, is it like all src you want to match or any specific string you want it to do?
              – RavinderSingh13
              Nov 22 at 11:59






            • 1




              Great effort! The first one didn't work, the last two worked. I believe getting a regexp to work for all variants is the problem. I'll have a look at it tomorrow.
              – user1801060
              Nov 23 at 18:56















            up vote
            1
            down vote













            EDIT3: Adding one more code here as per OP's new edit.



            awk  '
            / width.*content-width.*src/{
            sub(/ width.*content-width.*src/," src")
            sub(//>$/," age="25" sex="M"&")
            }
            /src.*width/{
            match($0,/src[^)]*/)
            val=substr($0,RSTART,RLENGTH+2)
            sub(/src.*/,"")
            $0=$0 OFS val OFS "age="25" sex="M"/>"
            }
            1
            ' Input_file






            EDIT2: For changing complete line with respect to OP's PS3 could you please try following.



            awk '/^Donald/{$0="new_line_value"} 1'  Input_file
            new_line_value
            new_line_value
            George Bush
            Steve Austin






            EDIT: Since OP has changed expected output so adding solution as per that output now too.



            awk '/^<fo:external-graphic src=.*/ && match($0,/src=.*)"/){$0=substr($0,1,RSTART+RLENGTH) " new_value_bla_bla_here.. />"} 1' Input_file






            Could you please try following(haven't tested it thoroughly since your expected output is not clear).



            awk '
            /^<fo:/ && match($0,/src=.*>/){
            $0=substr($0,1,RSTART-1) OFS "new_value_here.." OFS substr($0,RSTART+RLENGTH+1)
            }
            1
            ' Input_file


            In this code checking a line which starts from <fo: string and then trying to catch string from src= till / by match and replacing that captured text with new string here.



            In case you want to save output into Input_file itself then append > temp_file && mv temp_file Input_file in above code too.






            share|improve this answer























            • The second line is ok. The first line prints out: <fo:external-graphic width="auto" height="auto" content-width="36pt" src="url(file:/C:/Users/xxx/images/tip.svg)"/ new_value_bla_bla_here.. />. Please feel free to test your solution against the file I provided at the beginning of my question
              – user1801060
              Nov 22 at 10:35












            • @user1801060, check now and let me know then? I was not checking condition for string ^<fo:external-graphic src= check now once?
              – RavinderSingh13
              Nov 22 at 10:54










            • Perhaps the mistake is mine. Here's a screenshot of my result: imgur.com/aENVTyD
              – user1801060
              Nov 22 at 11:41










            • @user1801060, is it like all src you want to match or any specific string you want it to do?
              – RavinderSingh13
              Nov 22 at 11:59






            • 1




              Great effort! The first one didn't work, the last two worked. I believe getting a regexp to work for all variants is the problem. I'll have a look at it tomorrow.
              – user1801060
              Nov 23 at 18:56













            up vote
            1
            down vote










            up vote
            1
            down vote









            EDIT3: Adding one more code here as per OP's new edit.



            awk  '
            / width.*content-width.*src/{
            sub(/ width.*content-width.*src/," src")
            sub(//>$/," age="25" sex="M"&")
            }
            /src.*width/{
            match($0,/src[^)]*/)
            val=substr($0,RSTART,RLENGTH+2)
            sub(/src.*/,"")
            $0=$0 OFS val OFS "age="25" sex="M"/>"
            }
            1
            ' Input_file






            EDIT2: For changing complete line with respect to OP's PS3 could you please try following.



            awk '/^Donald/{$0="new_line_value"} 1'  Input_file
            new_line_value
            new_line_value
            George Bush
            Steve Austin






            EDIT: Since OP has changed expected output so adding solution as per that output now too.



            awk '/^<fo:external-graphic src=.*/ && match($0,/src=.*)"/){$0=substr($0,1,RSTART+RLENGTH) " new_value_bla_bla_here.. />"} 1' Input_file






            Could you please try following(haven't tested it thoroughly since your expected output is not clear).



            awk '
            /^<fo:/ && match($0,/src=.*>/){
            $0=substr($0,1,RSTART-1) OFS "new_value_here.." OFS substr($0,RSTART+RLENGTH+1)
            }
            1
            ' Input_file


            In this code checking a line which starts from <fo: string and then trying to catch string from src= till / by match and replacing that captured text with new string here.



            In case you want to save output into Input_file itself then append > temp_file && mv temp_file Input_file in above code too.






            share|improve this answer














            EDIT3: Adding one more code here as per OP's new edit.



            awk  '
            / width.*content-width.*src/{
            sub(/ width.*content-width.*src/," src")
            sub(//>$/," age="25" sex="M"&")
            }
            /src.*width/{
            match($0,/src[^)]*/)
            val=substr($0,RSTART,RLENGTH+2)
            sub(/src.*/,"")
            $0=$0 OFS val OFS "age="25" sex="M"/>"
            }
            1
            ' Input_file






            EDIT2: For changing complete line with respect to OP's PS3 could you please try following.



            awk '/^Donald/{$0="new_line_value"} 1'  Input_file
            new_line_value
            new_line_value
            George Bush
            Steve Austin






            EDIT: Since OP has changed expected output so adding solution as per that output now too.



            awk '/^<fo:external-graphic src=.*/ && match($0,/src=.*)"/){$0=substr($0,1,RSTART+RLENGTH) " new_value_bla_bla_here.. />"} 1' Input_file






            Could you please try following(haven't tested it thoroughly since your expected output is not clear).



            awk '
            /^<fo:/ && match($0,/src=.*>/){
            $0=substr($0,1,RSTART-1) OFS "new_value_here.." OFS substr($0,RSTART+RLENGTH+1)
            }
            1
            ' Input_file


            In this code checking a line which starts from <fo: string and then trying to catch string from src= till / by match and replacing that captured text with new string here.



            In case you want to save output into Input_file itself then append > temp_file && mv temp_file Input_file in above code too.







            share|improve this answer














            share|improve this answer



            share|improve this answer








            edited Nov 22 at 13:45

























            answered Nov 22 at 9:30









            RavinderSingh13

            24.4k41437




            24.4k41437












            • The second line is ok. The first line prints out: <fo:external-graphic width="auto" height="auto" content-width="36pt" src="url(file:/C:/Users/xxx/images/tip.svg)"/ new_value_bla_bla_here.. />. Please feel free to test your solution against the file I provided at the beginning of my question
              – user1801060
              Nov 22 at 10:35












            • @user1801060, check now and let me know then? I was not checking condition for string ^<fo:external-graphic src= check now once?
              – RavinderSingh13
              Nov 22 at 10:54










            • Perhaps the mistake is mine. Here's a screenshot of my result: imgur.com/aENVTyD
              – user1801060
              Nov 22 at 11:41










            • @user1801060, is it like all src you want to match or any specific string you want it to do?
              – RavinderSingh13
              Nov 22 at 11:59






            • 1




              Great effort! The first one didn't work, the last two worked. I believe getting a regexp to work for all variants is the problem. I'll have a look at it tomorrow.
              – user1801060
              Nov 23 at 18:56


















            • The second line is ok. The first line prints out: <fo:external-graphic width="auto" height="auto" content-width="36pt" src="url(file:/C:/Users/xxx/images/tip.svg)"/ new_value_bla_bla_here.. />. Please feel free to test your solution against the file I provided at the beginning of my question
              – user1801060
              Nov 22 at 10:35












            • @user1801060, check now and let me know then? I was not checking condition for string ^<fo:external-graphic src= check now once?
              – RavinderSingh13
              Nov 22 at 10:54










            • Perhaps the mistake is mine. Here's a screenshot of my result: imgur.com/aENVTyD
              – user1801060
              Nov 22 at 11:41










            • @user1801060, is it like all src you want to match or any specific string you want it to do?
              – RavinderSingh13
              Nov 22 at 11:59






            • 1




              Great effort! The first one didn't work, the last two worked. I believe getting a regexp to work for all variants is the problem. I'll have a look at it tomorrow.
              – user1801060
              Nov 23 at 18:56
















            The second line is ok. The first line prints out: <fo:external-graphic width="auto" height="auto" content-width="36pt" src="url(file:/C:/Users/xxx/images/tip.svg)"/ new_value_bla_bla_here.. />. Please feel free to test your solution against the file I provided at the beginning of my question
            – user1801060
            Nov 22 at 10:35






            The second line is ok. The first line prints out: <fo:external-graphic width="auto" height="auto" content-width="36pt" src="url(file:/C:/Users/xxx/images/tip.svg)"/ new_value_bla_bla_here.. />. Please feel free to test your solution against the file I provided at the beginning of my question
            – user1801060
            Nov 22 at 10:35














            @user1801060, check now and let me know then? I was not checking condition for string ^<fo:external-graphic src= check now once?
            – RavinderSingh13
            Nov 22 at 10:54




            @user1801060, check now and let me know then? I was not checking condition for string ^<fo:external-graphic src= check now once?
            – RavinderSingh13
            Nov 22 at 10:54












            Perhaps the mistake is mine. Here's a screenshot of my result: imgur.com/aENVTyD
            – user1801060
            Nov 22 at 11:41




            Perhaps the mistake is mine. Here's a screenshot of my result: imgur.com/aENVTyD
            – user1801060
            Nov 22 at 11:41












            @user1801060, is it like all src you want to match or any specific string you want it to do?
            – RavinderSingh13
            Nov 22 at 11:59




            @user1801060, is it like all src you want to match or any specific string you want it to do?
            – RavinderSingh13
            Nov 22 at 11:59




            1




            1




            Great effort! The first one didn't work, the last two worked. I believe getting a regexp to work for all variants is the problem. I'll have a look at it tomorrow.
            – user1801060
            Nov 23 at 18:56




            Great effort! The first one didn't work, the last two worked. I believe getting a regexp to work for all variants is the problem. I'll have a look at it tomorrow.
            – user1801060
            Nov 23 at 18:56


















            draft saved

            draft discarded




















































            Thanks for contributing an answer to Stack Overflow!


            • Please be sure to answer the question. Provide details and share your research!

            But avoid



            • Asking for help, clarification, or responding to other answers.

            • Making statements based on opinion; back them up with references or personal experience.


            To learn more, see our tips on writing great answers.





            Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


            Please pay close attention to the following guidance:


            • Please be sure to answer the question. Provide details and share your research!

            But avoid



            • Asking for help, clarification, or responding to other answers.

            • Making statements based on opinion; back them up with references or personal experience.


            To learn more, see our tips on writing great answers.




            draft saved


            draft discarded














            StackExchange.ready(
            function () {
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53427025%2fnested-conditional-search-and-in-place-substituition%23new-answer', 'question_page');
            }
            );

            Post as a guest















            Required, but never shown





















































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown

































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown







            Popular posts from this blog

            What visual should I use to simply compare current year value vs last year in Power BI desktop

            How to ignore python UserWarning in pytest?

            Alexandru Averescu