echo 1234 |   sed '
       /\n/ !G

I'm unable to comprehend the above sed code.

my understanding is:

first operation /\n/ !G ---> 1234\n(if \n is  not found it is appended at th end)
                s/\(.\)\(.*\n\)/&\2\1/ ----> 1234\n234\n1
                //D ----> \n234\n1(deletes upto newline and commands
                                   from the beginning are applied to the 
                                   existing pattern space)
second operation /\n/ !G ---> skipped since  \n234\n1 has newline now
                 s/\(.\)\(.*\n\)/&\2\1/ ----> \n234\n1234\n
                 //D ----> \n234\n1234\n

It seems I'm doing something wrong.

  • 2
    You can write it a little more legibly and efficiently as sed -e 'G;:1' -e 's/\(.\)\(.*\n\)/\2\1/;t1' -e 's/.//' Oct 31 '13 at 9:48

There is a loop in this code that get's confusing to see. This bit:


Keeps looping, shifting the characters 234\n1 to 34\n21 until we're left with \n4321, where it then drops out of the loop.

The description by catonmat is spot on so I'm including it here: 37. Reverse a line (emulates "rev" Unix command)..


The first line "/\n/ !G" appends a newline to the end of the pattern space if there was none.

The second line "s/\(.\)\(.*\n\)/&\2\1/" is a simple s/// expression which groups the first character as \1 and all the others as \2. Then it replaces the whole matched string with "&\2\1", where "&" is the whole matched text ("\1\2"). For example, if the input string is "1234" then after the s/// expression, it becomes "1234\n234\n1".

The third line is "//D". This statement is the key in this one-liner. An empty pattern // matches the last existing regex, so it's exactly the same as: /\(.\)\(.*\n\)/D. The "D" command deletes from the start of the input till the first newline and then resumes editing with first command in script. It creates a loop. As long as /\(.\)\(.*\n\)/ is satisfied, sed will resume all previous operations. After several loops, the text in the pattern space becomes "\n4321". Then /\(.\)\(.*\n\)/ fails and sed goes to the next command.

The fourth line "s/.//" removes the first character in the pattern space which is the newline char. The contents in pattern space becomes "4321" -- reverse of "1234".

There you have it, a line has been reversed.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.