Com o bash
shell, em um arquivo com linhas como as seguintes
first "line"
<second>line and so on
Gostaria de substituir uma ou mais ocorrências de "line"\n<second>
com other characters
e obter a cada vez:
first other characters line and so on
Então, eu tenho que substituir uma string por caracteres especiais como "
e <
e por um caractere de nova linha.
Depois de pesquisar entre as outras respostas, descobri que é sed
possível aceitar novas linhas no lado direito do comando (portanto, a other characters
string), mas não no esquerdo.
Existe uma maneira (mais simples que isso ) de obter esse resultado com sed
ou grep
?
text-processing
sed
grep
newlines
BowPark
fonte
fonte
\n
declaração ewline que você faz é por que eu pergunto. as pessoas raramente perguntam se podem fazer os//\n/
que você pode fazer com o GNUsed
, embora a maioria dos outrossed
rejeite essa fuga no lado direito. ainda assim, a\n
fuga funcionará à esquerda em qualquer POSIXsed
e você poderá traduzi-las de forma portável, comoy/c/\n/
se ela tivesse o mesmo efeitos/c/\n/g
e, portanto, nem sempre é tão útil.Respostas:
Três
sed
comandos diferentes :Todos os três se baseiam no
s///
comando básico de ubstitution:Todos eles também tentam tomar cuidado no manuseio da última linha, pois os
sed
s tendem a diferir em sua saída em casos extremos. Esse é o significado de$!
um endereço que corresponde a todas as linhas que!
não são as$
últimas.Todos também usam o
N
comando ext para anexar a próxima linha de entrada ao espaço do padrão após um\n
caractere ewline. Qualquer pessoa que estejased
há algum tempo aprenderá a confiar no\n
personagem ewline - porque a única maneira de conseguir um é explicitamente colocá-lo lá.Todos os três tentam ler o mínimo possível de informações antes de tomar uma ação -
sed
agem o mais rápido possível e não precisam ler um arquivo de entrada inteiro antes de fazê-lo.Embora façam tudo
N
, todos os três diferem em seus métodos de recursão.Primeiro Comando
O primeiro comando emprega um
N;P;D
loop muito simples . Esses três comandos são integrados a qualquer POSIX compatívelsed
e se complementam muito bem.N
- como já mencionado, anexa aN
linha de entrada ext ao espaço padrão após um\n
delimitador de linha de linha inserido .P
- comop
; eleP
cria espaço no padrão - mas apenas até o primeiro\n
caractere ewline que ocorre . E assim, dada a seguinte entrada / comando:printf %s\\n one two | sed '$!N;P;d'
sed
P
Rints apenas um . No entanto, com ...D
- comod
; eleD
elimina o espaço padrão e inicia outro ciclo de linha. Ao contráriod
,D
exclui apenas até a primeira linha de\n
ew que ocorre no espaço do padrão. Se houver mais espaço no padrão após o\n
caractere ewline,sed
inicia o próximo ciclo de linha com o que resta. Se od
no exemplo anterior foram substituídos com umD
, por exemplo,sed
seriaP
Rint tanto um e dois .Este comando ocorre apenas para linhas que não correspondem à
s///
instrução ubstitution. Como a ubstitutions///
remove o\n
ewline adicionado comN
, nunca resta nada quando sesed
D
elimina o espaço do padrão.Poderiam ser feitos testes para aplicar o
P
e / ouD
seletivamente, mas existem outros comandos que se encaixam melhor nessa estratégia. Como a recursão é implementada para manipular linhas consecutivas que correspondem apenas a parte da regra de substituição, sequências consecutivas de linhas correspondentes às duas extremidades das///
substituição não funcionam bem .:Dada esta entrada:
... imprime ...
No entanto, lida com
...bem.
Segundo comando
Este comando é muito semelhante ao terceiro. Ambos empregam um rótulo de
:b
fazenda /t
est (como também é demonstrado na resposta de Joeseph R. aqui ) e retornam a ele sob determinadas condições.-e :n -e
-sed
scripts portáteis delimitarão uma:
definição de rótulo com uma linha de\n
ew ou uma nova-e
instrução de xecution em linha .:n
- define um rótulo chamadon
. Isso pode ser retornado a qualquer momento combn
outn
.tn
- ot
comando est retorna para um rótulo especificado (ou, se nenhum for fornecido, sai do script para o ciclo de linha atual) se houver algumas///
substituição desde que o rótulo foi definido ou desde a última vez que foi chamadot
ests com êxito.Neste comando, a recursão ocorre para as linhas correspondentes. Se
sed
substituir com êxito o padrão por outros caracteres ,sed
retornará ao:n
rótulo e tentará novamente. Se umas///
substituição não for executada, osed
espaço de padrão é impresso automaticamente e inicia o próximo ciclo de linha.Isso tende a lidar melhor com seqüências consecutivas. Onde o último falhou, isso imprime:
Terceiro comando
Como mencionado, a lógica aqui é muito semelhante à anterior, mas o teste é mais explícito.
/"$/bn
- este ésed
o teste. Como ob
comando ranch é uma função desse endereço,sed
eleb
retornará somente:n
depois que um\n
ewline for acrescentado e o espaço do padrão ainda terminar com"
aspas duplas.Há o mínimo possível entre
N
eb
quanto possível - dessa maneira, ésed
possível reunir rapidamente, exatamente, o máximo de entrada necessário para garantir que a linha a seguir não corresponda à sua regra. As///
ubstituição difere aqui porque emprega ag
bandeira global - e, portanto, fará todas as substituições necessárias de uma só vez. Dada entrada idêntica, este comando é idêntico ao último.fonte
DATA
e como você recebe a entrada de texto?<<\DATA\ntext input\nDATA\n
está inserido , mas esse é apenas o texto entreguesed
pelo shell em um documento aqui . Funcionaria tão bem quantosed 'script' filename
ouprocess that writes to stdout | sed 'script'
. Isso ajuda?D
toda linha modificada é dupla? (Você usou-o como é necessário, talvez eu não seised
muito bem)D
porque, deD
outra forma,D
elimina da saída o que agora vê dobrado. Acabei de fazer uma edição - e posso expandir isso também em breve.D
assunto.Bem, eu posso pensar em algumas maneiras simples, mas nenhuma delas envolve
grep
(o que não substitui de qualquer maneira) oused
.Perl
Para substituir cada ocorrência de
"line"\n<second>
porother characters
, use:Ou, para tratar várias ocorrências consecutivas
"line"\n<second>
como uma e substituir todas elas por uma únicaother characters
, use:Exemplo:
O
-00
Perl faz com que o arquivo seja lido no "modo de parágrafo", o que significa que "linhas" são definidas por, em\n\n
vez de\n
, essencialmente, cada parágrafo ser tratado como uma linha. A substituição corresponde, portanto, a uma nova linha.awk
A mesma idéia básica, configuramos o separador de registros (
RS
) para\n\n
reduzir o arquivo inteiro, depois o separador de registros de saída para nada (caso contrário, uma nova linha extra é impressa) e, em seguida, usamos asub()
função para fazer a substituição.fonte
awk
deve serprint;}' file
. Preciso evitar o Perl e usar preferencialmentesed
, de qualquer maneira você sugeriu boas alternativas.leia o arquivo inteiro e faça uma substituição global:
fonte
${cmds}
é específico do GNU - a maioria dos outrossed
requer uma\n
linha de e-mail ou uma-e
pausa entrep
e}
. Você pode evitar os suportes completamente - e portably - e até mesmo evitar a inserção de um extra de\n
caráter ewline na primeira linha como:sed 'H;1h;$!d;x;s/"line"\n<second>/other characters /g'
sed -n '1{h;n};H; ${x; s/"line"\n<second>/other characters /g; p}'
- no entanto, isso está ficando impossível de manter.Aqui está uma variante da resposta de glenn que funcionará se você tiver várias ocorrências consecutivas (funciona
sed
apenas com GNU ):O
:x
é apenas um rótulo para ramificação. Basicamente, o que isso faz é que ele verifica a linha após a substituição e, se ainda corresponder"line"
, volta ao:x
rótulo (é o quebx
faz) e adiciona outra linha ao buffer e começa a processá-lo.fonte
sed
que leva seu manuseio de etiquetas não POSIX o suficiente para aceitar um espaço como um delimitador para a declaração de etiquetas. Você deve observar, porém, que qualquer outrosed
falhará lá - e falharáN
. O GNUsed
quebra as diretrizes do POSIX para imprimir o espaço do padrão antes de sair em umaN
na última linha, mas o POSIX deixa claro que, se umN
comando for lido na última linha, nada deverá ser impresso.v
comando do GNU, que é interrompido um no outro,sed
mas é um no-op nas versões 4 e superiores do GNU.sed -e :x -e '/"line"/{$!N' -e '};s/"line"\n<second>/other characters/;/"line"/bx'
.