Swap lines in text file only where containing strings using sed or ed?

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP











up vote
3
down vote

favorite












I need to swap these lines, only where the matching strings are in both lines:



before:



REF*CE*-------------------------
REF*1W*-------------------------


after:



REF*1W*-------------------------
REF*CE*-------------------------


I tried this, it didn't work:



ed -s testfile.txt <<<$'/REF*CE*/-0,/REF*CE*/+0m/REF*1W*/nwnq'









share|improve this question























  • the matching strings - by the prefix REF ?
    – RomanPerekhrest
    Jun 28 '17 at 18:24










  • REFCE and REF*1W* are matching strings
    – user5586678
    Jun 28 '17 at 18:27










  • Literal asterisks, or RE followed by zero or more Fs, followed by C, followed by zero or more Es?
    – DopeGhoti
    Jun 28 '17 at 19:44











  • yes, if both patterns match, swap lines
    – user5586678
    Jun 29 '17 at 19:39






  • 1




    Does your file contain other lines also? Are the given lines adjacent? How should non-adjacent REF lines be handled? Might your file contain more than two lines with the pattern REF? Should more pairs be swapped? What if there are an odd number of REF lines?
    – Wildcard
    Jun 30 '17 at 22:15














up vote
3
down vote

favorite












I need to swap these lines, only where the matching strings are in both lines:



before:



REF*CE*-------------------------
REF*1W*-------------------------


after:



REF*1W*-------------------------
REF*CE*-------------------------


I tried this, it didn't work:



ed -s testfile.txt <<<$'/REF*CE*/-0,/REF*CE*/+0m/REF*1W*/nwnq'









share|improve this question























  • the matching strings - by the prefix REF ?
    – RomanPerekhrest
    Jun 28 '17 at 18:24










  • REFCE and REF*1W* are matching strings
    – user5586678
    Jun 28 '17 at 18:27










  • Literal asterisks, or RE followed by zero or more Fs, followed by C, followed by zero or more Es?
    – DopeGhoti
    Jun 28 '17 at 19:44











  • yes, if both patterns match, swap lines
    – user5586678
    Jun 29 '17 at 19:39






  • 1




    Does your file contain other lines also? Are the given lines adjacent? How should non-adjacent REF lines be handled? Might your file contain more than two lines with the pattern REF? Should more pairs be swapped? What if there are an odd number of REF lines?
    – Wildcard
    Jun 30 '17 at 22:15












up vote
3
down vote

favorite









up vote
3
down vote

favorite











I need to swap these lines, only where the matching strings are in both lines:



before:



REF*CE*-------------------------
REF*1W*-------------------------


after:



REF*1W*-------------------------
REF*CE*-------------------------


I tried this, it didn't work:



ed -s testfile.txt <<<$'/REF*CE*/-0,/REF*CE*/+0m/REF*1W*/nwnq'









share|improve this question















I need to swap these lines, only where the matching strings are in both lines:



before:



REF*CE*-------------------------
REF*1W*-------------------------


after:



REF*1W*-------------------------
REF*CE*-------------------------


I tried this, it didn't work:



ed -s testfile.txt <<<$'/REF*CE*/-0,/REF*CE*/+0m/REF*1W*/nwnq'






text-processing sed ed






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Sep 6 '17 at 9:36









Kusalananda

114k15217347




114k15217347










asked Jun 28 '17 at 18:22









user5586678

213




213











  • the matching strings - by the prefix REF ?
    – RomanPerekhrest
    Jun 28 '17 at 18:24










  • REFCE and REF*1W* are matching strings
    – user5586678
    Jun 28 '17 at 18:27










  • Literal asterisks, or RE followed by zero or more Fs, followed by C, followed by zero or more Es?
    – DopeGhoti
    Jun 28 '17 at 19:44











  • yes, if both patterns match, swap lines
    – user5586678
    Jun 29 '17 at 19:39






  • 1




    Does your file contain other lines also? Are the given lines adjacent? How should non-adjacent REF lines be handled? Might your file contain more than two lines with the pattern REF? Should more pairs be swapped? What if there are an odd number of REF lines?
    – Wildcard
    Jun 30 '17 at 22:15
















  • the matching strings - by the prefix REF ?
    – RomanPerekhrest
    Jun 28 '17 at 18:24










  • REFCE and REF*1W* are matching strings
    – user5586678
    Jun 28 '17 at 18:27










  • Literal asterisks, or RE followed by zero or more Fs, followed by C, followed by zero or more Es?
    – DopeGhoti
    Jun 28 '17 at 19:44











  • yes, if both patterns match, swap lines
    – user5586678
    Jun 29 '17 at 19:39






  • 1




    Does your file contain other lines also? Are the given lines adjacent? How should non-adjacent REF lines be handled? Might your file contain more than two lines with the pattern REF? Should more pairs be swapped? What if there are an odd number of REF lines?
    – Wildcard
    Jun 30 '17 at 22:15















the matching strings - by the prefix REF ?
– RomanPerekhrest
Jun 28 '17 at 18:24




the matching strings - by the prefix REF ?
– RomanPerekhrest
Jun 28 '17 at 18:24












REFCE and REF*1W* are matching strings
– user5586678
Jun 28 '17 at 18:27




REFCE and REF*1W* are matching strings
– user5586678
Jun 28 '17 at 18:27












Literal asterisks, or RE followed by zero or more Fs, followed by C, followed by zero or more Es?
– DopeGhoti
Jun 28 '17 at 19:44





Literal asterisks, or RE followed by zero or more Fs, followed by C, followed by zero or more Es?
– DopeGhoti
Jun 28 '17 at 19:44













yes, if both patterns match, swap lines
– user5586678
Jun 29 '17 at 19:39




yes, if both patterns match, swap lines
– user5586678
Jun 29 '17 at 19:39




1




1




Does your file contain other lines also? Are the given lines adjacent? How should non-adjacent REF lines be handled? Might your file contain more than two lines with the pattern REF? Should more pairs be swapped? What if there are an odd number of REF lines?
– Wildcard
Jun 30 '17 at 22:15




Does your file contain other lines also? Are the given lines adjacent? How should non-adjacent REF lines be handled? Might your file contain more than two lines with the pattern REF? Should more pairs be swapped? What if there are an odd number of REF lines?
– Wildcard
Jun 30 '17 at 22:15










4 Answers
4






active

oldest

votes

















up vote
1
down vote













sed -e :a -e '$!N;s/^(REF*CE.*)n(REF*1W.*)/2n1/;ta' -e 'P;D' <testfile.txt 


  1. If we're not on the last line then append next line.

  2. Do a substitution on the current line that only occurs if it matches substring containing pattern 1 + newline + substring containing pattern 2. The substitution flips the two sub-strings. After substitution go back to label :a.

  3. If there was no match Print the pattern space as is. Then Delete the pattern space and start the cycle again.

Sample with some surrounding lines...



In:

XEF*CE*-------------------------
REF*CE*-------------------------
REF*1W*-------------------------
REF*2W*-------------------------

Out:


XEF*CE*-------------------------
REF*1W*-------------------------
REF*CE*-------------------------
REF*2W*-------------------------


More generally for any pattern1 and pattern2



sed -e :a 
-e "$!N; s/^(.*$pattern1.*)n(.*$pattern2.*)/2n1/;ta"
-e 'P;D' < inputfile





share|improve this answer






















  • I tried the sed command on my test file, and it didn't work. Here is the relevant section of the file: REF*BB*106497026~ REF*CE*NEW JERSEY~ REF*1W*723266637~ SVC*HC^S5102*78.5*78.5**1~
    – user5586678
    Jun 30 '17 at 13:59











  • Sorry, I should have tested a bit more. Hopefully this does the trick. Your testcases work for me.
    – B Layer
    Jun 30 '17 at 22:10

















up vote
0
down vote













We can get the desired effect by putting the matched line into hold buffer, reading next line and printing it, then swapping the hold buffer with pattern buffer and printing again.



bash-4.3$ sed -n '/^REF*CE/!p;/^REF*CE/h;n;p;x;p' input.txt
some line here
REF*BB*106497026---------------
REF*1W*723266637---------------
REF*CE*NEW JERSEY--------------
SVC*HC^S5102*78.5*78.5**1------
another line there





share|improve this answer






















  • Doesn't work with the case cited in the first comment below my answer.
    – B Layer
    Jun 30 '17 at 22:15










  • @BlairM. I just tested with the example OP mentioned. Works OK. Can you clarify what exactly doesn't work ?
    – Sergiy Kolodyazhnyy
    Jun 30 '17 at 22:21










  • As don_crissti mentioned try it where the first pattern repeats on consecutive lines. Mine didn't work with this case until I updated it. Yours seems to discard a line at some point.
    – B Layer
    Jun 30 '17 at 23:34







  • 1




    I would imagine that OP is not trying to solve only for the very specific case that he supplied and his comment to my answer suggests as much. Regardless I want my answer to be robust enough to work generally, matching consecutive patterned lines under any circumstance, so that other people may find it useful.
    – B Layer
    Jul 1 '17 at 0:17






  • 1




    @user5586678 I'm out, man, sorry. You're not paying attention to what anyone is saying ("add better examples of input/output to your question", "explain what didn't work with Blair M's answer", "please reply under my answer, not here", etc.) and I don't have infinite time to spend on this.
    – B Layer
    Jul 8 '17 at 0:52


















up vote
0
down vote













A general solution for how to swap two (possibly distant) lines that match particular regular expressions with ed:




  1. Copy one line to after the second line.


  2. Move the second line to after the original first line.


  3. Delete the first original line.

Or, with ed editing commands:



  1. /pat1/t/pat2/

  2. ?pat2?m/pat1/

  3. ?pat1?d

Example with the file



CLP*815900102*2*489.8*101.5*82.29*13*PVJLS03YP0000*13*7
AMT*AU*489.8
REF*6R*00000000002
DTM*472*20160528
CAS*OA*23*306.01
CAS*PR*2*82.29
SVC*HC:99212:25*489.8*101.5**1
AMT*B6*411.43


in which we'd like to swap the first AMT line with the second CAS line. pat1 will be ^AMT*AU and pat2 will be ^CAS*PR. Note that we need to escape the * for it to be treated literally in the regular expression.



I have annotated the changes below so that it's easier to see them. The XXX indicates the current position in the file after each operation.




  1. /^AMT*AU/t/^CAS*PR/ produces



    CLP*815900102*2*489.8*101.5*82.29*13*PVJLS03YP0000*13*7
    AMT*AU*489.8 <-- Line copied *from* here
    REF*6R*00000000002
    DTM*472*20160528
    CAS*OA*23*306.01
    CAS*PR*2*82.29
    AMT*AU*489.8 <-- Line copied *to* here (XXX)
    SVC*HC:99212:25*489.8*101.5**1
    AMT*B6*411.43



  2. ?^CAS*PR?m/^AMT*AU/ produces



    CLP*815900102*2*489.8*101.5*82.29*13*PVJLS03YP0000*13*7
    AMT*AU*489.8
    CAS*PR*2*82.29 <-- line moved here (XXX)
    REF*6R*00000000002
    DTM*472*20160528
    CAS*OA*23*306.01
    AMT*AU*489.8 <-- line previous to this deleted
    SVC*HC:99212:25*489.8*101.5**1
    AMT*B6*411.43



  3. ?^AMT*AU?d produces



    CLP*815900102*2*489.8*101.5*82.29*13*PVJLS03YP0000*13*7
    CAS*PR*2*82.29 <-- the line before this was removed (XXX)
    REF*6R*00000000002
    DTM*472*20160528
    CAS*OA*23*306.01
    AMT*AU*489.8
    SVC*HC:99212:25*489.8*101.5**1
    AMT*B6*411.43



As an easy-to-remember "one-liner":



pat1='^AMT*AU'; pat2='^CAS*PR'; printf '/%s/t/%s/n?%s?m/%s/n?%s?dnwqn' "$pat1" "$pat2" "$pat2" "$pat1" "$pat1" | ed -s file


Note that this is reversible by running the exact thing a second time, i.e. it doesn't matter which pattern is the first or second.






share|improve this answer






















  • Kusalananda, does this work if the pattern repeats multiple times in the file?
    – user5586678
    Sep 7 '17 at 11:52










  • @user5586678 It will pick the first occurrence of each pattern.
    – Kusalananda
    Sep 7 '17 at 12:00










  • @user5586678 Actually, the second step may become seriously messed up if pat1 occurs many times. It would be best to try to have as specific patterns as possible.
    – Kusalananda
    Sep 7 '17 at 12:02


















up vote
-1
down vote













I have simple solution like this:
Say, If you want swap a line that has "XXXX" with line that has "YYYY" in afile, providing only one line has "XXXX" and only one has "YYYY"



Example file is like this:
*ssss dddd
aaaa ffff
ddd rrrr
ddddd XXXX
ddddde
ffff
ffff
fff
eeee YYYY
ghghgh
hhhhh



My 'sed' command is sed 's/XXXX/ZZZZ/g;s/YYYY/XXXX/g;s/ZZZZ/YYYY/g'
Remember "ZZZZ" string should not be in the file anyware.






share|improve this answer








New contributor




Sarath Anura Hiyare Hewage is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.

















    Your Answer








    StackExchange.ready(function()
    var channelOptions =
    tags: "".split(" "),
    id: "106"
    ;
    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: false,
    noModals: true,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: null,
    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%2funix.stackexchange.com%2fquestions%2f373996%2fswap-lines-in-text-file-only-where-containing-strings-using-sed-or-ed%23new-answer', 'question_page');

    );

    Post as a guest






























    4 Answers
    4






    active

    oldest

    votes








    4 Answers
    4






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes








    up vote
    1
    down vote













    sed -e :a -e '$!N;s/^(REF*CE.*)n(REF*1W.*)/2n1/;ta' -e 'P;D' <testfile.txt 


    1. If we're not on the last line then append next line.

    2. Do a substitution on the current line that only occurs if it matches substring containing pattern 1 + newline + substring containing pattern 2. The substitution flips the two sub-strings. After substitution go back to label :a.

    3. If there was no match Print the pattern space as is. Then Delete the pattern space and start the cycle again.

    Sample with some surrounding lines...



    In:

    XEF*CE*-------------------------
    REF*CE*-------------------------
    REF*1W*-------------------------
    REF*2W*-------------------------

    Out:


    XEF*CE*-------------------------
    REF*1W*-------------------------
    REF*CE*-------------------------
    REF*2W*-------------------------


    More generally for any pattern1 and pattern2



    sed -e :a 
    -e "$!N; s/^(.*$pattern1.*)n(.*$pattern2.*)/2n1/;ta"
    -e 'P;D' < inputfile





    share|improve this answer






















    • I tried the sed command on my test file, and it didn't work. Here is the relevant section of the file: REF*BB*106497026~ REF*CE*NEW JERSEY~ REF*1W*723266637~ SVC*HC^S5102*78.5*78.5**1~
      – user5586678
      Jun 30 '17 at 13:59











    • Sorry, I should have tested a bit more. Hopefully this does the trick. Your testcases work for me.
      – B Layer
      Jun 30 '17 at 22:10














    up vote
    1
    down vote













    sed -e :a -e '$!N;s/^(REF*CE.*)n(REF*1W.*)/2n1/;ta' -e 'P;D' <testfile.txt 


    1. If we're not on the last line then append next line.

    2. Do a substitution on the current line that only occurs if it matches substring containing pattern 1 + newline + substring containing pattern 2. The substitution flips the two sub-strings. After substitution go back to label :a.

    3. If there was no match Print the pattern space as is. Then Delete the pattern space and start the cycle again.

    Sample with some surrounding lines...



    In:

    XEF*CE*-------------------------
    REF*CE*-------------------------
    REF*1W*-------------------------
    REF*2W*-------------------------

    Out:


    XEF*CE*-------------------------
    REF*1W*-------------------------
    REF*CE*-------------------------
    REF*2W*-------------------------


    More generally for any pattern1 and pattern2



    sed -e :a 
    -e "$!N; s/^(.*$pattern1.*)n(.*$pattern2.*)/2n1/;ta"
    -e 'P;D' < inputfile





    share|improve this answer






















    • I tried the sed command on my test file, and it didn't work. Here is the relevant section of the file: REF*BB*106497026~ REF*CE*NEW JERSEY~ REF*1W*723266637~ SVC*HC^S5102*78.5*78.5**1~
      – user5586678
      Jun 30 '17 at 13:59











    • Sorry, I should have tested a bit more. Hopefully this does the trick. Your testcases work for me.
      – B Layer
      Jun 30 '17 at 22:10












    up vote
    1
    down vote










    up vote
    1
    down vote









    sed -e :a -e '$!N;s/^(REF*CE.*)n(REF*1W.*)/2n1/;ta' -e 'P;D' <testfile.txt 


    1. If we're not on the last line then append next line.

    2. Do a substitution on the current line that only occurs if it matches substring containing pattern 1 + newline + substring containing pattern 2. The substitution flips the two sub-strings. After substitution go back to label :a.

    3. If there was no match Print the pattern space as is. Then Delete the pattern space and start the cycle again.

    Sample with some surrounding lines...



    In:

    XEF*CE*-------------------------
    REF*CE*-------------------------
    REF*1W*-------------------------
    REF*2W*-------------------------

    Out:


    XEF*CE*-------------------------
    REF*1W*-------------------------
    REF*CE*-------------------------
    REF*2W*-------------------------


    More generally for any pattern1 and pattern2



    sed -e :a 
    -e "$!N; s/^(.*$pattern1.*)n(.*$pattern2.*)/2n1/;ta"
    -e 'P;D' < inputfile





    share|improve this answer














    sed -e :a -e '$!N;s/^(REF*CE.*)n(REF*1W.*)/2n1/;ta' -e 'P;D' <testfile.txt 


    1. If we're not on the last line then append next line.

    2. Do a substitution on the current line that only occurs if it matches substring containing pattern 1 + newline + substring containing pattern 2. The substitution flips the two sub-strings. After substitution go back to label :a.

    3. If there was no match Print the pattern space as is. Then Delete the pattern space and start the cycle again.

    Sample with some surrounding lines...



    In:

    XEF*CE*-------------------------
    REF*CE*-------------------------
    REF*1W*-------------------------
    REF*2W*-------------------------

    Out:


    XEF*CE*-------------------------
    REF*1W*-------------------------
    REF*CE*-------------------------
    REF*2W*-------------------------


    More generally for any pattern1 and pattern2



    sed -e :a 
    -e "$!N; s/^(.*$pattern1.*)n(.*$pattern2.*)/2n1/;ta"
    -e 'P;D' < inputfile






    share|improve this answer














    share|improve this answer



    share|improve this answer








    edited Jul 1 '17 at 0:28

























    answered Jun 30 '17 at 10:48









    B Layer

    3,9541525




    3,9541525











    • I tried the sed command on my test file, and it didn't work. Here is the relevant section of the file: REF*BB*106497026~ REF*CE*NEW JERSEY~ REF*1W*723266637~ SVC*HC^S5102*78.5*78.5**1~
      – user5586678
      Jun 30 '17 at 13:59











    • Sorry, I should have tested a bit more. Hopefully this does the trick. Your testcases work for me.
      – B Layer
      Jun 30 '17 at 22:10
















    • I tried the sed command on my test file, and it didn't work. Here is the relevant section of the file: REF*BB*106497026~ REF*CE*NEW JERSEY~ REF*1W*723266637~ SVC*HC^S5102*78.5*78.5**1~
      – user5586678
      Jun 30 '17 at 13:59











    • Sorry, I should have tested a bit more. Hopefully this does the trick. Your testcases work for me.
      – B Layer
      Jun 30 '17 at 22:10















    I tried the sed command on my test file, and it didn't work. Here is the relevant section of the file: REF*BB*106497026~ REF*CE*NEW JERSEY~ REF*1W*723266637~ SVC*HC^S5102*78.5*78.5**1~
    – user5586678
    Jun 30 '17 at 13:59





    I tried the sed command on my test file, and it didn't work. Here is the relevant section of the file: REF*BB*106497026~ REF*CE*NEW JERSEY~ REF*1W*723266637~ SVC*HC^S5102*78.5*78.5**1~
    – user5586678
    Jun 30 '17 at 13:59













    Sorry, I should have tested a bit more. Hopefully this does the trick. Your testcases work for me.
    – B Layer
    Jun 30 '17 at 22:10




    Sorry, I should have tested a bit more. Hopefully this does the trick. Your testcases work for me.
    – B Layer
    Jun 30 '17 at 22:10












    up vote
    0
    down vote













    We can get the desired effect by putting the matched line into hold buffer, reading next line and printing it, then swapping the hold buffer with pattern buffer and printing again.



    bash-4.3$ sed -n '/^REF*CE/!p;/^REF*CE/h;n;p;x;p' input.txt
    some line here
    REF*BB*106497026---------------
    REF*1W*723266637---------------
    REF*CE*NEW JERSEY--------------
    SVC*HC^S5102*78.5*78.5**1------
    another line there





    share|improve this answer






















    • Doesn't work with the case cited in the first comment below my answer.
      – B Layer
      Jun 30 '17 at 22:15










    • @BlairM. I just tested with the example OP mentioned. Works OK. Can you clarify what exactly doesn't work ?
      – Sergiy Kolodyazhnyy
      Jun 30 '17 at 22:21










    • As don_crissti mentioned try it where the first pattern repeats on consecutive lines. Mine didn't work with this case until I updated it. Yours seems to discard a line at some point.
      – B Layer
      Jun 30 '17 at 23:34







    • 1




      I would imagine that OP is not trying to solve only for the very specific case that he supplied and his comment to my answer suggests as much. Regardless I want my answer to be robust enough to work generally, matching consecutive patterned lines under any circumstance, so that other people may find it useful.
      – B Layer
      Jul 1 '17 at 0:17






    • 1




      @user5586678 I'm out, man, sorry. You're not paying attention to what anyone is saying ("add better examples of input/output to your question", "explain what didn't work with Blair M's answer", "please reply under my answer, not here", etc.) and I don't have infinite time to spend on this.
      – B Layer
      Jul 8 '17 at 0:52















    up vote
    0
    down vote













    We can get the desired effect by putting the matched line into hold buffer, reading next line and printing it, then swapping the hold buffer with pattern buffer and printing again.



    bash-4.3$ sed -n '/^REF*CE/!p;/^REF*CE/h;n;p;x;p' input.txt
    some line here
    REF*BB*106497026---------------
    REF*1W*723266637---------------
    REF*CE*NEW JERSEY--------------
    SVC*HC^S5102*78.5*78.5**1------
    another line there





    share|improve this answer






















    • Doesn't work with the case cited in the first comment below my answer.
      – B Layer
      Jun 30 '17 at 22:15










    • @BlairM. I just tested with the example OP mentioned. Works OK. Can you clarify what exactly doesn't work ?
      – Sergiy Kolodyazhnyy
      Jun 30 '17 at 22:21










    • As don_crissti mentioned try it where the first pattern repeats on consecutive lines. Mine didn't work with this case until I updated it. Yours seems to discard a line at some point.
      – B Layer
      Jun 30 '17 at 23:34







    • 1




      I would imagine that OP is not trying to solve only for the very specific case that he supplied and his comment to my answer suggests as much. Regardless I want my answer to be robust enough to work generally, matching consecutive patterned lines under any circumstance, so that other people may find it useful.
      – B Layer
      Jul 1 '17 at 0:17






    • 1




      @user5586678 I'm out, man, sorry. You're not paying attention to what anyone is saying ("add better examples of input/output to your question", "explain what didn't work with Blair M's answer", "please reply under my answer, not here", etc.) and I don't have infinite time to spend on this.
      – B Layer
      Jul 8 '17 at 0:52













    up vote
    0
    down vote










    up vote
    0
    down vote









    We can get the desired effect by putting the matched line into hold buffer, reading next line and printing it, then swapping the hold buffer with pattern buffer and printing again.



    bash-4.3$ sed -n '/^REF*CE/!p;/^REF*CE/h;n;p;x;p' input.txt
    some line here
    REF*BB*106497026---------------
    REF*1W*723266637---------------
    REF*CE*NEW JERSEY--------------
    SVC*HC^S5102*78.5*78.5**1------
    another line there





    share|improve this answer














    We can get the desired effect by putting the matched line into hold buffer, reading next line and printing it, then swapping the hold buffer with pattern buffer and printing again.



    bash-4.3$ sed -n '/^REF*CE/!p;/^REF*CE/h;n;p;x;p' input.txt
    some line here
    REF*BB*106497026---------------
    REF*1W*723266637---------------
    REF*CE*NEW JERSEY--------------
    SVC*HC^S5102*78.5*78.5**1------
    another line there






    share|improve this answer














    share|improve this answer



    share|improve this answer








    edited Jun 30 '17 at 22:20

























    answered Jun 30 '17 at 22:10









    Sergiy Kolodyazhnyy

    8,02011951




    8,02011951











    • Doesn't work with the case cited in the first comment below my answer.
      – B Layer
      Jun 30 '17 at 22:15










    • @BlairM. I just tested with the example OP mentioned. Works OK. Can you clarify what exactly doesn't work ?
      – Sergiy Kolodyazhnyy
      Jun 30 '17 at 22:21










    • As don_crissti mentioned try it where the first pattern repeats on consecutive lines. Mine didn't work with this case until I updated it. Yours seems to discard a line at some point.
      – B Layer
      Jun 30 '17 at 23:34







    • 1




      I would imagine that OP is not trying to solve only for the very specific case that he supplied and his comment to my answer suggests as much. Regardless I want my answer to be robust enough to work generally, matching consecutive patterned lines under any circumstance, so that other people may find it useful.
      – B Layer
      Jul 1 '17 at 0:17






    • 1




      @user5586678 I'm out, man, sorry. You're not paying attention to what anyone is saying ("add better examples of input/output to your question", "explain what didn't work with Blair M's answer", "please reply under my answer, not here", etc.) and I don't have infinite time to spend on this.
      – B Layer
      Jul 8 '17 at 0:52

















    • Doesn't work with the case cited in the first comment below my answer.
      – B Layer
      Jun 30 '17 at 22:15










    • @BlairM. I just tested with the example OP mentioned. Works OK. Can you clarify what exactly doesn't work ?
      – Sergiy Kolodyazhnyy
      Jun 30 '17 at 22:21










    • As don_crissti mentioned try it where the first pattern repeats on consecutive lines. Mine didn't work with this case until I updated it. Yours seems to discard a line at some point.
      – B Layer
      Jun 30 '17 at 23:34







    • 1




      I would imagine that OP is not trying to solve only for the very specific case that he supplied and his comment to my answer suggests as much. Regardless I want my answer to be robust enough to work generally, matching consecutive patterned lines under any circumstance, so that other people may find it useful.
      – B Layer
      Jul 1 '17 at 0:17






    • 1




      @user5586678 I'm out, man, sorry. You're not paying attention to what anyone is saying ("add better examples of input/output to your question", "explain what didn't work with Blair M's answer", "please reply under my answer, not here", etc.) and I don't have infinite time to spend on this.
      – B Layer
      Jul 8 '17 at 0:52
















    Doesn't work with the case cited in the first comment below my answer.
    – B Layer
    Jun 30 '17 at 22:15




    Doesn't work with the case cited in the first comment below my answer.
    – B Layer
    Jun 30 '17 at 22:15












    @BlairM. I just tested with the example OP mentioned. Works OK. Can you clarify what exactly doesn't work ?
    – Sergiy Kolodyazhnyy
    Jun 30 '17 at 22:21




    @BlairM. I just tested with the example OP mentioned. Works OK. Can you clarify what exactly doesn't work ?
    – Sergiy Kolodyazhnyy
    Jun 30 '17 at 22:21












    As don_crissti mentioned try it where the first pattern repeats on consecutive lines. Mine didn't work with this case until I updated it. Yours seems to discard a line at some point.
    – B Layer
    Jun 30 '17 at 23:34





    As don_crissti mentioned try it where the first pattern repeats on consecutive lines. Mine didn't work with this case until I updated it. Yours seems to discard a line at some point.
    – B Layer
    Jun 30 '17 at 23:34





    1




    1




    I would imagine that OP is not trying to solve only for the very specific case that he supplied and his comment to my answer suggests as much. Regardless I want my answer to be robust enough to work generally, matching consecutive patterned lines under any circumstance, so that other people may find it useful.
    – B Layer
    Jul 1 '17 at 0:17




    I would imagine that OP is not trying to solve only for the very specific case that he supplied and his comment to my answer suggests as much. Regardless I want my answer to be robust enough to work generally, matching consecutive patterned lines under any circumstance, so that other people may find it useful.
    – B Layer
    Jul 1 '17 at 0:17




    1




    1




    @user5586678 I'm out, man, sorry. You're not paying attention to what anyone is saying ("add better examples of input/output to your question", "explain what didn't work with Blair M's answer", "please reply under my answer, not here", etc.) and I don't have infinite time to spend on this.
    – B Layer
    Jul 8 '17 at 0:52





    @user5586678 I'm out, man, sorry. You're not paying attention to what anyone is saying ("add better examples of input/output to your question", "explain what didn't work with Blair M's answer", "please reply under my answer, not here", etc.) and I don't have infinite time to spend on this.
    – B Layer
    Jul 8 '17 at 0:52











    up vote
    0
    down vote













    A general solution for how to swap two (possibly distant) lines that match particular regular expressions with ed:




    1. Copy one line to after the second line.


    2. Move the second line to after the original first line.


    3. Delete the first original line.

    Or, with ed editing commands:



    1. /pat1/t/pat2/

    2. ?pat2?m/pat1/

    3. ?pat1?d

    Example with the file



    CLP*815900102*2*489.8*101.5*82.29*13*PVJLS03YP0000*13*7
    AMT*AU*489.8
    REF*6R*00000000002
    DTM*472*20160528
    CAS*OA*23*306.01
    CAS*PR*2*82.29
    SVC*HC:99212:25*489.8*101.5**1
    AMT*B6*411.43


    in which we'd like to swap the first AMT line with the second CAS line. pat1 will be ^AMT*AU and pat2 will be ^CAS*PR. Note that we need to escape the * for it to be treated literally in the regular expression.



    I have annotated the changes below so that it's easier to see them. The XXX indicates the current position in the file after each operation.




    1. /^AMT*AU/t/^CAS*PR/ produces



      CLP*815900102*2*489.8*101.5*82.29*13*PVJLS03YP0000*13*7
      AMT*AU*489.8 <-- Line copied *from* here
      REF*6R*00000000002
      DTM*472*20160528
      CAS*OA*23*306.01
      CAS*PR*2*82.29
      AMT*AU*489.8 <-- Line copied *to* here (XXX)
      SVC*HC:99212:25*489.8*101.5**1
      AMT*B6*411.43



    2. ?^CAS*PR?m/^AMT*AU/ produces



      CLP*815900102*2*489.8*101.5*82.29*13*PVJLS03YP0000*13*7
      AMT*AU*489.8
      CAS*PR*2*82.29 <-- line moved here (XXX)
      REF*6R*00000000002
      DTM*472*20160528
      CAS*OA*23*306.01
      AMT*AU*489.8 <-- line previous to this deleted
      SVC*HC:99212:25*489.8*101.5**1
      AMT*B6*411.43



    3. ?^AMT*AU?d produces



      CLP*815900102*2*489.8*101.5*82.29*13*PVJLS03YP0000*13*7
      CAS*PR*2*82.29 <-- the line before this was removed (XXX)
      REF*6R*00000000002
      DTM*472*20160528
      CAS*OA*23*306.01
      AMT*AU*489.8
      SVC*HC:99212:25*489.8*101.5**1
      AMT*B6*411.43



    As an easy-to-remember "one-liner":



    pat1='^AMT*AU'; pat2='^CAS*PR'; printf '/%s/t/%s/n?%s?m/%s/n?%s?dnwqn' "$pat1" "$pat2" "$pat2" "$pat1" "$pat1" | ed -s file


    Note that this is reversible by running the exact thing a second time, i.e. it doesn't matter which pattern is the first or second.






    share|improve this answer






















    • Kusalananda, does this work if the pattern repeats multiple times in the file?
      – user5586678
      Sep 7 '17 at 11:52










    • @user5586678 It will pick the first occurrence of each pattern.
      – Kusalananda
      Sep 7 '17 at 12:00










    • @user5586678 Actually, the second step may become seriously messed up if pat1 occurs many times. It would be best to try to have as specific patterns as possible.
      – Kusalananda
      Sep 7 '17 at 12:02















    up vote
    0
    down vote













    A general solution for how to swap two (possibly distant) lines that match particular regular expressions with ed:




    1. Copy one line to after the second line.


    2. Move the second line to after the original first line.


    3. Delete the first original line.

    Or, with ed editing commands:



    1. /pat1/t/pat2/

    2. ?pat2?m/pat1/

    3. ?pat1?d

    Example with the file



    CLP*815900102*2*489.8*101.5*82.29*13*PVJLS03YP0000*13*7
    AMT*AU*489.8
    REF*6R*00000000002
    DTM*472*20160528
    CAS*OA*23*306.01
    CAS*PR*2*82.29
    SVC*HC:99212:25*489.8*101.5**1
    AMT*B6*411.43


    in which we'd like to swap the first AMT line with the second CAS line. pat1 will be ^AMT*AU and pat2 will be ^CAS*PR. Note that we need to escape the * for it to be treated literally in the regular expression.



    I have annotated the changes below so that it's easier to see them. The XXX indicates the current position in the file after each operation.




    1. /^AMT*AU/t/^CAS*PR/ produces



      CLP*815900102*2*489.8*101.5*82.29*13*PVJLS03YP0000*13*7
      AMT*AU*489.8 <-- Line copied *from* here
      REF*6R*00000000002
      DTM*472*20160528
      CAS*OA*23*306.01
      CAS*PR*2*82.29
      AMT*AU*489.8 <-- Line copied *to* here (XXX)
      SVC*HC:99212:25*489.8*101.5**1
      AMT*B6*411.43



    2. ?^CAS*PR?m/^AMT*AU/ produces



      CLP*815900102*2*489.8*101.5*82.29*13*PVJLS03YP0000*13*7
      AMT*AU*489.8
      CAS*PR*2*82.29 <-- line moved here (XXX)
      REF*6R*00000000002
      DTM*472*20160528
      CAS*OA*23*306.01
      AMT*AU*489.8 <-- line previous to this deleted
      SVC*HC:99212:25*489.8*101.5**1
      AMT*B6*411.43



    3. ?^AMT*AU?d produces



      CLP*815900102*2*489.8*101.5*82.29*13*PVJLS03YP0000*13*7
      CAS*PR*2*82.29 <-- the line before this was removed (XXX)
      REF*6R*00000000002
      DTM*472*20160528
      CAS*OA*23*306.01
      AMT*AU*489.8
      SVC*HC:99212:25*489.8*101.5**1
      AMT*B6*411.43



    As an easy-to-remember "one-liner":



    pat1='^AMT*AU'; pat2='^CAS*PR'; printf '/%s/t/%s/n?%s?m/%s/n?%s?dnwqn' "$pat1" "$pat2" "$pat2" "$pat1" "$pat1" | ed -s file


    Note that this is reversible by running the exact thing a second time, i.e. it doesn't matter which pattern is the first or second.






    share|improve this answer






















    • Kusalananda, does this work if the pattern repeats multiple times in the file?
      – user5586678
      Sep 7 '17 at 11:52










    • @user5586678 It will pick the first occurrence of each pattern.
      – Kusalananda
      Sep 7 '17 at 12:00










    • @user5586678 Actually, the second step may become seriously messed up if pat1 occurs many times. It would be best to try to have as specific patterns as possible.
      – Kusalananda
      Sep 7 '17 at 12:02













    up vote
    0
    down vote










    up vote
    0
    down vote









    A general solution for how to swap two (possibly distant) lines that match particular regular expressions with ed:




    1. Copy one line to after the second line.


    2. Move the second line to after the original first line.


    3. Delete the first original line.

    Or, with ed editing commands:



    1. /pat1/t/pat2/

    2. ?pat2?m/pat1/

    3. ?pat1?d

    Example with the file



    CLP*815900102*2*489.8*101.5*82.29*13*PVJLS03YP0000*13*7
    AMT*AU*489.8
    REF*6R*00000000002
    DTM*472*20160528
    CAS*OA*23*306.01
    CAS*PR*2*82.29
    SVC*HC:99212:25*489.8*101.5**1
    AMT*B6*411.43


    in which we'd like to swap the first AMT line with the second CAS line. pat1 will be ^AMT*AU and pat2 will be ^CAS*PR. Note that we need to escape the * for it to be treated literally in the regular expression.



    I have annotated the changes below so that it's easier to see them. The XXX indicates the current position in the file after each operation.




    1. /^AMT*AU/t/^CAS*PR/ produces



      CLP*815900102*2*489.8*101.5*82.29*13*PVJLS03YP0000*13*7
      AMT*AU*489.8 <-- Line copied *from* here
      REF*6R*00000000002
      DTM*472*20160528
      CAS*OA*23*306.01
      CAS*PR*2*82.29
      AMT*AU*489.8 <-- Line copied *to* here (XXX)
      SVC*HC:99212:25*489.8*101.5**1
      AMT*B6*411.43



    2. ?^CAS*PR?m/^AMT*AU/ produces



      CLP*815900102*2*489.8*101.5*82.29*13*PVJLS03YP0000*13*7
      AMT*AU*489.8
      CAS*PR*2*82.29 <-- line moved here (XXX)
      REF*6R*00000000002
      DTM*472*20160528
      CAS*OA*23*306.01
      AMT*AU*489.8 <-- line previous to this deleted
      SVC*HC:99212:25*489.8*101.5**1
      AMT*B6*411.43



    3. ?^AMT*AU?d produces



      CLP*815900102*2*489.8*101.5*82.29*13*PVJLS03YP0000*13*7
      CAS*PR*2*82.29 <-- the line before this was removed (XXX)
      REF*6R*00000000002
      DTM*472*20160528
      CAS*OA*23*306.01
      AMT*AU*489.8
      SVC*HC:99212:25*489.8*101.5**1
      AMT*B6*411.43



    As an easy-to-remember "one-liner":



    pat1='^AMT*AU'; pat2='^CAS*PR'; printf '/%s/t/%s/n?%s?m/%s/n?%s?dnwqn' "$pat1" "$pat2" "$pat2" "$pat1" "$pat1" | ed -s file


    Note that this is reversible by running the exact thing a second time, i.e. it doesn't matter which pattern is the first or second.






    share|improve this answer














    A general solution for how to swap two (possibly distant) lines that match particular regular expressions with ed:




    1. Copy one line to after the second line.


    2. Move the second line to after the original first line.


    3. Delete the first original line.

    Or, with ed editing commands:



    1. /pat1/t/pat2/

    2. ?pat2?m/pat1/

    3. ?pat1?d

    Example with the file



    CLP*815900102*2*489.8*101.5*82.29*13*PVJLS03YP0000*13*7
    AMT*AU*489.8
    REF*6R*00000000002
    DTM*472*20160528
    CAS*OA*23*306.01
    CAS*PR*2*82.29
    SVC*HC:99212:25*489.8*101.5**1
    AMT*B6*411.43


    in which we'd like to swap the first AMT line with the second CAS line. pat1 will be ^AMT*AU and pat2 will be ^CAS*PR. Note that we need to escape the * for it to be treated literally in the regular expression.



    I have annotated the changes below so that it's easier to see them. The XXX indicates the current position in the file after each operation.




    1. /^AMT*AU/t/^CAS*PR/ produces



      CLP*815900102*2*489.8*101.5*82.29*13*PVJLS03YP0000*13*7
      AMT*AU*489.8 <-- Line copied *from* here
      REF*6R*00000000002
      DTM*472*20160528
      CAS*OA*23*306.01
      CAS*PR*2*82.29
      AMT*AU*489.8 <-- Line copied *to* here (XXX)
      SVC*HC:99212:25*489.8*101.5**1
      AMT*B6*411.43



    2. ?^CAS*PR?m/^AMT*AU/ produces



      CLP*815900102*2*489.8*101.5*82.29*13*PVJLS03YP0000*13*7
      AMT*AU*489.8
      CAS*PR*2*82.29 <-- line moved here (XXX)
      REF*6R*00000000002
      DTM*472*20160528
      CAS*OA*23*306.01
      AMT*AU*489.8 <-- line previous to this deleted
      SVC*HC:99212:25*489.8*101.5**1
      AMT*B6*411.43



    3. ?^AMT*AU?d produces



      CLP*815900102*2*489.8*101.5*82.29*13*PVJLS03YP0000*13*7
      CAS*PR*2*82.29 <-- the line before this was removed (XXX)
      REF*6R*00000000002
      DTM*472*20160528
      CAS*OA*23*306.01
      AMT*AU*489.8
      SVC*HC:99212:25*489.8*101.5**1
      AMT*B6*411.43



    As an easy-to-remember "one-liner":



    pat1='^AMT*AU'; pat2='^CAS*PR'; printf '/%s/t/%s/n?%s?m/%s/n?%s?dnwqn' "$pat1" "$pat2" "$pat2" "$pat1" "$pat1" | ed -s file


    Note that this is reversible by running the exact thing a second time, i.e. it doesn't matter which pattern is the first or second.







    share|improve this answer














    share|improve this answer



    share|improve this answer








    edited Sep 6 '17 at 9:48

























    answered Sep 6 '17 at 9:30









    Kusalananda

    114k15217347




    114k15217347











    • Kusalananda, does this work if the pattern repeats multiple times in the file?
      – user5586678
      Sep 7 '17 at 11:52










    • @user5586678 It will pick the first occurrence of each pattern.
      – Kusalananda
      Sep 7 '17 at 12:00










    • @user5586678 Actually, the second step may become seriously messed up if pat1 occurs many times. It would be best to try to have as specific patterns as possible.
      – Kusalananda
      Sep 7 '17 at 12:02

















    • Kusalananda, does this work if the pattern repeats multiple times in the file?
      – user5586678
      Sep 7 '17 at 11:52










    • @user5586678 It will pick the first occurrence of each pattern.
      – Kusalananda
      Sep 7 '17 at 12:00










    • @user5586678 Actually, the second step may become seriously messed up if pat1 occurs many times. It would be best to try to have as specific patterns as possible.
      – Kusalananda
      Sep 7 '17 at 12:02
















    Kusalananda, does this work if the pattern repeats multiple times in the file?
    – user5586678
    Sep 7 '17 at 11:52




    Kusalananda, does this work if the pattern repeats multiple times in the file?
    – user5586678
    Sep 7 '17 at 11:52












    @user5586678 It will pick the first occurrence of each pattern.
    – Kusalananda
    Sep 7 '17 at 12:00




    @user5586678 It will pick the first occurrence of each pattern.
    – Kusalananda
    Sep 7 '17 at 12:00












    @user5586678 Actually, the second step may become seriously messed up if pat1 occurs many times. It would be best to try to have as specific patterns as possible.
    – Kusalananda
    Sep 7 '17 at 12:02





    @user5586678 Actually, the second step may become seriously messed up if pat1 occurs many times. It would be best to try to have as specific patterns as possible.
    – Kusalananda
    Sep 7 '17 at 12:02











    up vote
    -1
    down vote













    I have simple solution like this:
    Say, If you want swap a line that has "XXXX" with line that has "YYYY" in afile, providing only one line has "XXXX" and only one has "YYYY"



    Example file is like this:
    *ssss dddd
    aaaa ffff
    ddd rrrr
    ddddd XXXX
    ddddde
    ffff
    ffff
    fff
    eeee YYYY
    ghghgh
    hhhhh



    My 'sed' command is sed 's/XXXX/ZZZZ/g;s/YYYY/XXXX/g;s/ZZZZ/YYYY/g'
    Remember "ZZZZ" string should not be in the file anyware.






    share|improve this answer








    New contributor




    Sarath Anura Hiyare Hewage is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
    Check out our Code of Conduct.





















      up vote
      -1
      down vote













      I have simple solution like this:
      Say, If you want swap a line that has "XXXX" with line that has "YYYY" in afile, providing only one line has "XXXX" and only one has "YYYY"



      Example file is like this:
      *ssss dddd
      aaaa ffff
      ddd rrrr
      ddddd XXXX
      ddddde
      ffff
      ffff
      fff
      eeee YYYY
      ghghgh
      hhhhh



      My 'sed' command is sed 's/XXXX/ZZZZ/g;s/YYYY/XXXX/g;s/ZZZZ/YYYY/g'
      Remember "ZZZZ" string should not be in the file anyware.






      share|improve this answer








      New contributor




      Sarath Anura Hiyare Hewage is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.



















        up vote
        -1
        down vote










        up vote
        -1
        down vote









        I have simple solution like this:
        Say, If you want swap a line that has "XXXX" with line that has "YYYY" in afile, providing only one line has "XXXX" and only one has "YYYY"



        Example file is like this:
        *ssss dddd
        aaaa ffff
        ddd rrrr
        ddddd XXXX
        ddddde
        ffff
        ffff
        fff
        eeee YYYY
        ghghgh
        hhhhh



        My 'sed' command is sed 's/XXXX/ZZZZ/g;s/YYYY/XXXX/g;s/ZZZZ/YYYY/g'
        Remember "ZZZZ" string should not be in the file anyware.






        share|improve this answer








        New contributor




        Sarath Anura Hiyare Hewage is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
        Check out our Code of Conduct.









        I have simple solution like this:
        Say, If you want swap a line that has "XXXX" with line that has "YYYY" in afile, providing only one line has "XXXX" and only one has "YYYY"



        Example file is like this:
        *ssss dddd
        aaaa ffff
        ddd rrrr
        ddddd XXXX
        ddddde
        ffff
        ffff
        fff
        eeee YYYY
        ghghgh
        hhhhh



        My 'sed' command is sed 's/XXXX/ZZZZ/g;s/YYYY/XXXX/g;s/ZZZZ/YYYY/g'
        Remember "ZZZZ" string should not be in the file anyware.







        share|improve this answer








        New contributor




        Sarath Anura Hiyare Hewage is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
        Check out our Code of Conduct.









        share|improve this answer



        share|improve this answer






        New contributor




        Sarath Anura Hiyare Hewage is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
        Check out our Code of Conduct.









        answered 24 mins ago









        Sarath Anura Hiyare Hewage

        1




        1




        New contributor




        Sarath Anura Hiyare Hewage is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
        Check out our Code of Conduct.





        New contributor





        Sarath Anura Hiyare Hewage is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
        Check out our Code of Conduct.






        Sarath Anura Hiyare Hewage is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
        Check out our Code of Conduct.



























             

            draft saved


            draft discarded















































             


            draft saved


            draft discarded














            StackExchange.ready(
            function ()
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2funix.stackexchange.com%2fquestions%2f373996%2fswap-lines-in-text-file-only-where-containing-strings-using-sed-or-ed%23new-answer', 'question_page');

            );

            Post as a guest













































































            Popular posts from this blog

            How to check contact read email or not when send email to Individual?

            Displaying single band from multi-band raster using QGIS

            How many registers does an x86_64 CPU actually have?