3

Input file looks like:

1 0 0 000 3444
2 3 3 456 6875
3 0 0 023 3300
4 2 2 211 1000

first: I want to have 2 copies of each line:

1 0 0 000 3444
1 0 0 000 3444
2 3 3 456 6875
2 3 3 456 6875
3 0 0 023 3300
3 0 0 023 3300
4 2 2 211 1000
4 2 2 211 1000

second: in first copy of each line 3 should be replaced by 2 and 4 should be replaced by 1 and in the second copy of each line, 3 should be replaced by 1 and 4 should be replaced by 2 (the first column is row names and row numbers should not change). So, final output becomes:

1 0 0 000 2111
1 0 0 000 1222
2 2 2 156 6875
2 1 1 256 6875
3 0 0 022 2200
3 0 0 021 1100
4 2 2 211 1000
4 2 2 211 1000

any suggestion please? I tried this but it does not work:

awk '
      { tmp = $2; gsub("3", "2", $2); gsub("4", "1", $2); print}
      { $2 = tmp; gsub("3", "1", $2); gsub("4", "2", $2); print}
    ' < input > output
  • Put everything is a single action. – Satō Katsura Aug 17 '16 at 16:54
2

How to double each line: see here...
As to your second request, just save 1st field and the entire line into variables then do the first change, set the 1st field to the initial value and print then restore the line content, do the second change, set the 1st field again to the initial value and print:

awk '{t=$1;l=$0;gsub(/3/, "2");gsub(/4/, "1");$1=t;print}
{$0=l;gsub(/3/, "1");gsub(/4/, "2");$1=t;print}' infile
1

Perl seems to be quite nice for this kind of thing since it has a built-in tr

$ perl -alne '
    @tmp=@F; 
    tr/34/21/ for @tmp[1..4]; print join " ", @tmp; 
    tr/34/12/ for @F[1..4]; print join " ", @F
  ' file
1 0 0 000 2111
1 0 0 000 1222
2 2 2 156 6875
2 1 1 256 6875
3 0 0 022 2200
3 0 0 021 1100
4 2 2 211 1000
4 2 2 211 1000
1

Not exactly elegant, but it's possible with GNU sed:

h              # save in hold
s_^[0-9]\{1,\} __ # remove first column
s_3_A_g        # change 3 and 4 to A and B
s_4_B_g
x              # swap with hold
s_ .*$__       # remove everything but first column
G              # append from hold
s_\n_ _        # join lines (with space)
h              # save in hold space again
s_A_2_g        # first output -> 2, 1
s_B_1_g
p              # print first line
g              # restore from hold 
s_A_1_g        # second output -> 1, 2
s_B_2_g
# end of script, second line printed automatically

This saves the first column (so that it won't be changed), and builds a version of the line with all the remaining 3s and 4s changed to As and Bs respectively. That line is then used for both outputs, first with 2 and 1, then the other way around.

sed -f script.sed input > output

This assumes that your input only contains numbers and spaces, ie. A and B don't already appear there.

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.