Isso (adaptado de aqui ) deve fazer o que você precisa, embora o de Perl do @rici seja muito mais simples:
$ sed -r ':a;s/(("[0-9,]*",?)*"[0-9,]*),//;ta; s/""/","/g;
s/"([0-9]*)",?/,/g ' file
56,72,123454,x,y,"foo,a,b,bar"
56,92,1234,x,y,"foo,a,b,bar"
56,72,12345478765467,x,y,"foo,a,b,bar"
56,72,x,y,"foo,a,b,bar",123454,
56,72,x,y,"foo,a,b,bar",123454,45578492,"bar,foo"
Explicação
-
:a
: define um rótulo chamadoa
. -
s/(("[0-9,]*",?)*"[0-9,]*),//
: Este precisa ser dividido- Antes de mais nada, use esta construção:
(foo(bar))
,será
foobar
eserá
bar
. -
"[0-9,]*",?
: corresponde a 0 ou mais de0-9
ou,
, seguido por 0 ou 1,
. -
("[0-9,]*",?)*
: corresponde a 0 ou mais dos acima. -
"[0-9,]*
: corresponde a 0 ou mais de0-9
ou,
que aparecem imediatamente após"
- Antes de mais nada, use esta construção:
-
ta;
: volte para o rótuloa
e execute novamente se a substituição foi bem sucedida. -
s/""/","/g;
: pós-processamento. Substitua""
por","
. -
s/"([0-9]*)",?/,/g
: remova todas as aspas em torno dos números.
Isso pode ser mais fácil de entender com outro exemplo:
$ echo '"1,2,3,4"' | sed -nr ':a;s/(("[0-9,]*",?)*"[0-9,]*),//;p;ta;'
"1,2,34"
"1,234"
"1234"
"1234"
Assim, enquanto você pode encontrar um número logo após uma citação e seguido por uma vírgula e outro número, junte os dois números juntos e repita o processo até que não seja mais possível.
Neste ponto, acredito que seja útil mencionar uma citação de info sed
que aparece na seção descrevendo funções avançadas, como o rótulo usado acima (obrigado por descobrir se @Braiam):
In most cases, use of these commands indicates that you are probably better off programming in something like 'awk' or Perl.