Substituir apenas a primeira instância de um caractere

2

por exemplo eu tenho arquivo scv que parece

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

O que eu quero fazer é substituir a primeira vírgula , pelo ponto-e-vírgula ; . A posição da primeira vírgula pode ser variável ( a nas linhas n e m podem ter diferentes comprimentos). Finalmente meu arquivo será parecido com

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

As outras vírgulas devem permanecer. Alguém pode me dizer a solução mais simples?

PS minha solução não funciona: sed '/s/,/;/g' file.csv

    
por Guforu 25.07.2016 / 15:18

2 respostas

2

Solução bash pura

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

Ou apenas por diversão

paste -d\; <(cut -d, -f1 file.csv) <(cut -d, -f1 --complement file.csv)
    
por 25.07.2016 / 16:02
12

O g em:

sed 's/,/;/g'

é para globalmente , isto é, para substituir todas as ocorrências de , por ; .

Se você quiser fazer apenas uma substituição por linha, tire o g :

sed 's/,/;/'

E para completar:

Você também pode especificar qual ocorrência será substituída. Por exemplo, para substituir apenas a segunda ocorrência:

sed 's/,/;/2'

Com o GNU sed , você também pode substituir todas as ocorrências a partir do segundo (na verdade, todas exceto a primeira) com:

sed 's/,/;/2g'

Para executar duas substituições, neste caso:

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

Quando fica mais complicado é quando o padrão pode corresponder à substituição (ou partes dela), por exemplo, ao substituir , por <,> . sed não possui mecanismo integrado para resolver isso. Você pode querer usar perl nesse caso:

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

perl -pe é perl sed mode (observe que a sintaxe regex é diferente). Com o sinalizador e do operador s/// , a substituição é considerada como código. Lá, substituímos , por <,> apenas quando nosso contador incrementado for < 2. Caso contrário, substituiremos o , por si mesmo ( $& , na verdade, referindo-se à sequência de correspondência como & no comando sed ' s ).

Você pode generalizar isso para um intervalo ou um conjunto de substituições. Como para 3 rd a 5 th e 7 th a 9 th :

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

Nota

Suponho que seja um erro de digitação, mas o

sed '/s/,/;/g'

o comando que você escreveu na sua pergunta é algo completamente diferente.

Isso está fazendo:

sed '/start/,/end/g'

em que start é s e end é ; . Ou seja, aplicando o comando g (substitua o espaço de padrão pelo conteúdo do espaço de suspensão (vazio aqui como você nunca contém nada)) para seções do arquivo entre uma que contenha s e a próxima que contenha ; .

    
por 25.07.2016 / 15:38