9

I have a text file as follows:

test1,test2,test3 test4,test5 test6,test7,test8,test9,test10 test11,test12,test13,test14 

How can I replace commas with semicolons, starting with the second one (and continuing to the last one)?

I want to get output as follows:

test1,test2;test3 test4,test5 test6,test7;test8;test9;test10 test11,test12;test13;test14 
1
  • 4
    Your question title doesn't match your question body. Do you want nth to (or through) mth, or do you want nth through last, no matter how many there are? And do you specifically want 2nd through last, or do you want a general solution that can easily be changed to substitute the 4th through the last, or the 17th through the last? Commented Sep 6, 2016 at 6:08

4 Answers 4

14

This can be done with this,

$ sed -e 's/,/;/g' -e 's/;/,/1' infile test1,test2;test3 test4,test5 test6,test7;test8;test9;test10 test11,test12;test13;test14 

Explanation

  • s/,/;/g replaces all occurrence of , with ;

  • s/;/,/1 replaces the first occurrence of ; with ,


If you have GNU sed, you can also try this simple and handy,

sed 's/,/;/2g' infile 
2
  • 4
    didn't know about sed 's/,/;/2g' on GNU sed, cool one! Commented Sep 6, 2016 at 7:28
  • 7
    What I don't like about this solution is that it breaks down unexpectedly when you replace "test1" with a string containing a semicolon. Commented Sep 6, 2016 at 16:22
7

If the input might already have semicolons in it, we have to be careful:

$ sed 's/,/\n/g; s/\n/,/; s/\n/;/g' input test1,test2;test3 test4,test5 test6,test7;test8;test9;test10 test11,test12;test13;test14 

Since sed reads the input line-by-line, there will be no newline characters in normal input. So, we can replace all the commas with newlines and we know that there will be no confusion. Next we restore the first newline back to a comma. Lastly, we replace all remaining newlines with a semicolon.

In more detail:

  • s/,/\n/g replaces all commas with newlines.

  • s/\n/,/ replaces the first newline with a comma.

  • s/\n/;/g replaces all remaining newlines with semicolons.

1
  • I thought of sed 's/,/\n/; s/,/;/g; s/\n/,/', which is very similar to your answer, except mine has only one global command. Can you identify a situation where your command works better than mine? Commented Aug 31, 2018 at 4:56
2

Using awk:

awk '{gsub(",", ";"); sub(";", ","); print}' file.txt 
  • gsub(",", ";") replaces all , with ;

  • sub(";", ",") replaces the first ; with ,

Example:

% cat file.txt test1,test2,test3 test4,test5 test6,test7,test8,test9,test10 test11,test12,test13,test14 % awk '{gsub(",", ";"); sub(";", ","); print}' file.txt test1,test2;test3 test4,test5 test6,test7;test8;test9;test10 test11,test12;test13;test14 
1
  • If the question is to keep the first two semicolon, you can add another sub function. Commented Sep 9, 2016 at 4:45
2
$ cat ip.txt test1,test2,test3 test4,test5 test6,test7,test8,test9,test10 test11,test12,test13,test14 test15 $ perl -F, -ane 'print "$F[0]"; print ",".join(";",@F[1..$#F]) if($#F > 0)' ip.txt test1,test2;test3 test4,test5 test6,test7;test8;test9;test10 test11,test12;test13;test14 test15 


Another way:

perl -F'/(,)/,$_,2' -ane '$F[2] =~ s/,/;/g; print @F' 
  • /(,)/,$_,2 split $_ (the input line) into two based on , Since (,) is used, it captures the separator as well resulting in three elements as explained below
  • $F[0] gets first field, $F[1] will get , if present
  • $F[2] gets remaining fields if present


Yet another way, emulating sed 's/,/;/2g'

perl -pe '$c=0; s/,/++$c<2 ? $& : ";"/ge' ip.txt 
  • initialize counter for every line
  • when substituting, check counter value as needed
  • the e modifier allows Perl code in replacement section

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.