Você teria que fazer isso em um loop:
s/\(^.*title="[^" ]*\) \([^"]*".*$\)/_/
ou (mais rápido)
s/\(title="[^" ]*\) \([^"]*"\)/_/
e use o recurso de teste e ramificação de sed, tentando novamente o substituto até que nenhuma outra alteração seja feita. O ponto dos padrões neste comando é dividir a linha no primeiro (restante) espaço e substituir esse espaço por um sublinhado.
Aqui está um script:
#!/bin/sh
sed -e ':loop' \
-e 's/\(title="[^" ]*\) \([^"]*"\)/_/' \
-e 't loop' <foo.in >foo.out
diff -u foo.in foo.out
A resposta inicial usou um padrão mais amplo, mas @ g-man comentou que não era necessário. Foi mais lento, como ilustrado pelo timing sed em um arquivo de 10Mb (testado com o GNU sed no Debian 7):
$ ./foo1
27.03user 0.01system 0:27.18elapsed 99%CPU (0avgtext+0avgdata 1104maxresident)k
0inputs+0outputs (0major+333minor)pagefaults 0swaps
9.54user 0.00system 0:09.60elapsed 99%CPU (0avgtext+0avgdata 972maxresident)k
0inputs+0outputs (0major+301minor)pagefaults 0swaps
Com o OSX, a diferença não é tanto:
$ ./foo1
real 0m11.943s
user 0m11.897s
sys 0m0.024s
real 0m5.858s
user 0m5.839s
sys 0m0.014s
Curiosamente, o padrão mais amplo não funciona com o sed do Solaris (mas o menor faz). Ele não corresponde a nenhum dos extremos da linha dentro do agrupamento \(
e \)
, enquanto o BSD e o GNU fazem isso. Da mesma forma, funciona com o HPUX 11.31 e o AIX 7.1
O POSIX sed usa BREs e o recurso de agrupamento é coberto por 9.3.6 BREs que correspondem a vários caracteres :
A subexpression can be defined within a BRE by enclosing it between the character pairs
"\("
and"\)"
. Such a subexpression shall match whatever it would have matched without the "(" and ")", except that anchoring within subexpressions is optional behavior; see BRE Expression Anchoring. Subexpressions can be arbitrarily nested.
9.3.8 Fixação da Expressão BRE explica o termo:
A BRE can be limited to matching strings that begin or end a line; this is called "anchoring".
Portanto, no contexto do padrão à medida que é implementado, essa é uma limitação conhecida do Solaris sed
, que o padrão permite como comportamento "opcional".
Leitura adicional:
- 3.7 Comandos para gurus de sed (descreve rótulos e loops)