I am trying to do a assignment for university, but I am currently stuck. The goal is to read some phone numbers and reverse the order of the first 3 digits and put them in brackets. I can get it to read the phone numbers but not do the reversal of the digits.

ex: input

214 4234-5555

ex: output

412 4234-5555

this is what I have so far

sed -r "s/([0-9]), ([0-9]), ([0-9])/\3\2\1/g" phone.txt

To modify OP's attempt

$ cat ip.txt
214 4234-5555
foo 123 4533-3242

$ sed -r 's/([0-9])([0-9])([0-9])/\3\2\1/' ip.txt
412 4234-5555
foo 321 4533-3242

$ # adding parenthesis as well
$ sed -r 's/([0-9])([0-9])([0-9])/(\3\2\1)/' ip.txt
(412) 4234-5555
foo (321) 4533-3242

$ # if ERE is not supported
$ sed 's/\([0-9]\)\([0-9]\)\([0-9]\)/(\3\2\1)/' ip.txt
(412) 4234-5555
foo (321) 4533-3242
  • Note that some sed implementation would need -E instead of -r
  • Use single quotes unless you need interpolation, see also https://mywiki.wooledge.org/Quotes
  • ([0-9]), ([0-9]), ([0-9]) means matching 3 digits separated by comma and space
  • g modifier is needed if all matches in a line should be changed

For a generic solution, i.e defining number of digits to reverse as a numeric argument

$ perl -pe 's/\d{3}/reverse $&/e' ip.txt
412 4234-5555
foo 321 4533-3242
$ perl -pe 's/\d{3}/sprintf "(%s)", scalar reverse $&/e' ip.txt
(412) 4234-5555
foo (321) 4533-3242
  • 1
    +1'ed, good answer, especially perl . You may want to include POSIX grouping \([0-9]\) since POSIX sed doesn't have -r , neither does FreeBSD sed. Feb 19 '18 at 5:55
  • 1
    @SergiyKolodyazhnyy, FreeBSD's sed now does support -r for compatibility with GNU sed. GNU sed now also supports -E for compatibility with BSDs and also because it will be the one specified in the next major version of the POSIX specification. Feb 19 '18 at 16:19

Here's a very long, convoluted, and probably unnecessary sed, but here it is nonetheless because fun:

sed -re 'h;    s/^([0-9]*) *(.*)/\1\n/;  :1 s/(.)(.*\n)/\2\1/;t1;  s/.//;  s/^(.*)$/\(\1\)/; x;s/([0-9]{3})(.*)/\2/;x;G;s/\n//'

This works as so:

      # pretend 214 4234-5555 is the current line
h;    # copy the current line into hold space
s/^([0-9]*) *(.*)/\1\n/;  # keep only first 3 numbers, 214
:1 s/(.)(.*\n)/\2\1/;t1;  s/.//;  # reversing string in sed, 
                                  # see notes below; 214 becomes 412
s/^(.*)$/\(\1\)/;  # After string is reversed, add brackets; (412)
x;s/([0-9]{3})(.*)/\2/; # swap hold and pattern buffer, 
                        # delete first 3 chars; 
                        # pattern space now is <space>4234-5555

x;G;s/\n// # swap again, append hold buffer to pattern buffer; 
            # now pattern buffer is (412)<newline> 4234-5555; 
            # finally delete newline; we get (412) 4234-5555

And that's how it looks like in action:

$ printf "214 4234-5555\n123 3333\n" | sed -re 'h;    s/^([0-9]*) *(.*)/\1\n/;  :1 s/(.)(.*\n)/\2\1/;t1;  s/.//;  s/^(.*)$/\(\1\)/; x;s/([0-9]{3})(.*)/\2/;x;G;s/\n//'
(412) 4234-5555
(321) 3333

Note: String reversal originally found on Stephane Chazelas's comment



I have used below method get the same result

i=`awk '{print $1}' example.txt| rev`
awk -v i="$i" '{print i,$2}' example.txt


412 4234-5555


sed  's/\(.\)\(.\)\(.\)/\3\2\1/' example.txt


412 4234-5555
  • I think your first line is missing some command substitution.
    – Jeff Schaller
    Feb 20 '18 at 3:21
  • @JeffSchaller Added the ` in first line which was missing. As checked it working fine now. Kindly let me know for any confusion Feb 20 '18 at 15:16
  • Still no parenthesis; and what about when there’s more than one line of input? Any comment to the OP to teach them what was wrong with their attempt? Otherwise they’re stuck copy-pasting solutions that they don’t understand.
    – Jeff Schaller
    Feb 20 '18 at 16:02

If you have the number in phone.txt as "xxx xxx-xxxx", then you can use the below:


echo '('$(cat phone.txt | cut -d ' ' -f1 | rev)')'

  • 1
    That only prints the 1st three numbers reversed, it removes the rest. And this will print one parenthesis at the top of the file, one at the bottom and everything else in the middle. You also don't need the cat, just cut -d ' ' -f1 phone.txt | rev would do the same (not very helpful) thing.
    – terdon
    Feb 19 '18 at 10:32

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.