Replace only first instance of a character

20,868

Solution 1

Pure bash solution

while IFS=\, read -r a b ; do echo "$a;$b" ; done <file.csv

Or just for fun

paste -d\; <(cut -d, -f1 file.csv) <(cut -d, -f1 --complement file.csv)

Solution 2

The g in:

sed 's/,/;/g'

is for globally, that is to substitute all occurrences of , with ;.

If you want to do only one substitution per line, take off the g:

sed 's/,/;/'

And for completeness:

You can also specify which occurrence to substitute. For instance, to substitute only the second occurrence:

sed 's/,/;/2'

With GNU sed, you can also substitute all occurrences starting from the second one (in effect, all but the first one) with:

sed 's/,/;/2g'

To perform two substitutions, in this case:

sed 's/,/;/;s/,/;/'

Where it gets more complicated is when the pattern can match the substitution (or parts of it), for instance when substituting , with <,>. sed has no built-in mechanism to address that. You may want to use perl instead in that case:

perl -pe '$i = 0; s/,/$i++ < 2 ? "<,>" : $&/ge'

perl -pe is perl's sed mode (note that the regex syntax is different). With the e flag of the s/// operator, the replacement is considered as code. There, we replace , with <,> only when our incremented counter is < 2. Otherwise, we replace the , with itself ($& actually referring to the matched string like & in sed's s command).

You can generalise that for a range or set of substitutions. Like for 3rd to 5th and 7th to 9th:

perl -pe '$i = 0; s/,/$i++;
   $i >=3 && $i <= 5 || $i >= 7 && $i <= 9 ? "<,>" : $&/ge'

To replace only the first occurrence in the whole input (as opposed to in each line):

sed -e 's/,/;/;t done' -e b -e :done -e 'n;b done'

That is, upon the first successful substitution, go into a loop that just prints the rest of the input.

With GNU sed, you can use the pseudo address 0:

sed '0,/,/s//;/'

Note

I suppose it's a typo, but the

sed '/s/,/;/g'

command you wrote in your question is something completely different.

That's doing:

sed '/start/,/end/g'

where start is s and end is ;. That is, applying the g command (replace the pattern space with the content of the hold space (empty here as you never hold anything)) for sections of the file in between one that contains s and the next one that contains ;.

Share:
20,868

Related videos on Youtube

Guforu
Author by

Guforu

Updated on September 18, 2022

Comments

  • Guforu
    Guforu over 1 year

    for example I have scv file which looks like

    a1, b1, c1, d1
    a2, b2, c2, d2
    a3, b3, c3, d3
    

    What I want to do is to replace the first comma , with the semicolon ;. The position of first comma can be variable (a in the rows n and m can have different lengths). Finally my file shall look like

    a1; b1, c1, d1
    a2; b2, c2, d2
    a3; b3, c3, d3
    

    The other commas have to remain. Can somebody please tell me the most simple solution?

    PS my solution doesn't work: sed '/s/,/;/g' file.csv

    • Costas
      Costas almost 8 years
      Do sed 's/,/;/' file.csv satisfy you?
    • Guforu
      Guforu almost 8 years
      no, I have got next error message: sed: -e expression #1, char 7: missing command
    • Costas
      Costas almost 8 years
      Do you miss quotes?
    • Stéphane Chazelas
      Stéphane Chazelas almost 8 years
      @Gufory, g is to change all comas. Without it, it changes only the first. See also sed 's/,/;/2' to change the second only and with GNU sed, sed 's/,/;/2g' to change all but the first.
    • Costas
      Costas almost 8 years
      With g sed change all commas in line, without it - just first. It cannot be true sed "s/,/;/g" do work and sed "s/,/;/" gets error. If you sence with sed try while IFS=\, read a b ; do echo "$a;$b" ; done <file.csv
    • Guforu
      Guforu almost 8 years
      Wow, this is exactly the solution! Now is everything works! Thank you a lot!
    • ygreaney
      ygreaney almost 8 years
      I"ve submitted an edit (peer-review pending) to change the title, as this explicitly is NOT about a specific position, but about the first occurrence, of the character.
  • Stéphane Chazelas
    Stéphane Chazelas almost 8 years
    Try the first one on an input like 1,2, or 1\,2 or 1. See also Why is using a shell loop to process text considered bad practice?
  • Costas
    Costas almost 8 years
    @StéphaneChazelas Thank you for comment, I have -r option added.
  • Stéphane Chazelas
    Stéphane Chazelas almost 8 years
    good. That addresses 1\,2, but not the 1,2, or 1 cases though. Note that , is not special, you don't need to quote it.
  • Nux
    Nux over 5 years
    Note that to only replace 1st occurence in a file (not in a line) you need to do something else. See: linuxconfig.org/…
  • Stéphane Chazelas
    Stéphane Chazelas over 5 years
    @Nux. Thanks, I've added a section about that.