Para alguns problemas como combinar um padrão em um número desconhecido de linhas ou "substituir a última ocorrência de ...", a opção -z
GNU sed
é realmente útil. Como posso conseguir a mesma coisa portátil?
Exemplo: tenho um arquivo
yellow, green,
blue, black, purple,
orange,
white, red, brown
are some colours
e quero substituir a última vírgula do arquivo por and
. Observe que não se sabe em qual linha ou onde está a vírgula. Com GNU sed
eu posso fazer
sed -z 's/\(.*\),/ \1 and/'
para obter a saída desejada
yellow, green,
blue, black, purple,
orange,
white, red and brown
are some colours
Como posso fazer isso de forma portátil, que rodará com qualquer POSIX sed
?
No POSIX puro
sed
, você precisa colar todas as linhas sozinho. Enquanto algumas pessoas fazem issoN
dentro de um loop, a abordagem mais fácil é anexar ao espaço de espera com oH;1h;$!d;x
padrão:H
acrescenta cada linha ao espaço de espera. Infelizmente, anexar a primeira linha adicionará uma nova linha ao início do buffer, então1h
substituirá o espaço de retenção da primeira linha para evitar a nova linha errada.$!d
encerrará o processamento de todas as linhas, exceto a última. Eles não precisam ser impressos, pois são armazenados no espaço de esperax
será executado somente após a última linha (para todas as outras linhas, od
processamento do comando parou) e iráx
alterar o espaço de espera e o espaço de padrão, então após este comando todo o arquivo que foi coletado no espaço de espera estará no espaço de padrão , assim como seria com a-z
opção GNUsed
. Claro que você também pode usarg
em vez dex
, mas isso produzirá muitas cópias, entãox
é mais rápido.Assim, o script para o exemplo ficará assim:
Observe que processar um arquivo como esse não é uma boa ideia para arquivos muito grandes, pois isso usará muita memória RAM.
sed é para fazer s/old/new simples em strings individuais, isso é tudo. Quase sempre que você se encontra usando construções diferentes de s, g e p (com -n) e certamente sempre que se encontra falando sobre "hold space" você está usando a ferramenta errada. Para algo mais complicado do que s/old/new, como esta tarefa, você deve usar apenas awk. O seguinte funcionará usando qualquer awk em qualquer shell em qualquer caixa UNIX, não armazena o arquivo inteiro na memória e é trivial ajustar se/quando você quiser fazer qualquer outra coisa no texto:
Você PODERIA fazer o trabalho mais brevemente em awk, sugando o arquivo inteiro na memória e escrevendo esta runa enigmática:
mas o ponto é que, ao contrário do sed, você não precisa.