# Reverse the order of first 3 digits in a line

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`
• `([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'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. – Sergiy Kolodyazhnyy Feb 19 '18 at 5:55
• @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. – Stéphane Chazelas 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

Method1

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
``````

Output

``````412 4234-5555
``````

Method2

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

output

``````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 – Praveen Kumar BS 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:

# !/bin/bash

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

• 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