Eu tenho um seguinte arquivo:
<head>
<title>this is a title</title>
<style>
here goes a style sheet
</style>
</head>
Eu preciso retirar o <title>
elemento dele, com sed
. Atualmente eu uso
cat test.html | sed 's/<title>.*<\/title>//'
e funciona, mas não entendo como me livrar da linha em branco. Ou seja, atualmente a saída é
<head>
<style>
here goes a style sheet
</style>
</head>
Considerando que eu quero que seja
<head>
<style>
here goes a style sheet
</style>
</head>
Para isso, tentei adicionar \s*
or \n*
, usando tanto GNU quanto BSD sed
,
cat test.html | sed 's/<title>.*<\/title>\s*//'
cat test.html | sed 's/<title>.*<\/title>\n*//'
mas isso não ajudou. O que estou fazendo de errado?
Editar: a <title>
linha não precisa estar em uma linha separada. Ou seja, às vezes o arquivo inteiro pode ser apenas uma linha:
<head><title>this is a title</title><style>here goes a style sheet</style></head>
Nesse caso, a saída desejada é
<head><style>here goes a style sheet</style></head>
O
s
comando emsed
modifica linhas. Para excluir linhas, use od
comando. Supondo que otitle
nó, incluindo seu valor, esteja em uma única linha no documento de entrada, você poderia fazer isso com(usando
,
como um delimitador alternativo para o endereço a ser excluído.)Seria mais rápido (menos pensar) de usar
grep -v
:Porém, por se tratar de um arquivo XML, eu usaria uma ferramenta que entendesse esse formato de documento estruturado. O texto abaixo usa
xmlstarlet
e não se importa se otitle
valor do nó contém novas linhas ou se o próprio nó contém atributos. Ele excluiria apenas otitle
nó abaixo do nó de nível superiorhead
e nada mais, enquantosed
andgrep
, sem saber sobre a estrutura do documento, excluiria cegamente qualquer linha que correspondesse ao padrão fornecido.Se a adição da declaração XML for indesejada, use
xmlstarlet
com sua opção-O
(ou ).--omit-decl
Você também pode fazer edição "no local" com-L
(ou--inplace
).Com essas opções em vigor e usando sintaxe abreviada:
Se o documento for um documento HTML (não XHTML, que já é XML), você poderá
xmlstarlet
convertê-lo em XML antes de editá-lo, usandoPor exemplo
Observe que precisamos usar o caminho
/html/head/title
em vez do/head/title
, porque ohead
nó deve estar contido em umhtml
nó para que seja um arquivo XHTML válido (se fosse um arquivo XML desde o início, poderíamos obviamente pular esta etapa completamente).Se você não tem e não pode instalar ferramentas compatíveis com XML, use qualquer awk (uma ferramenta POSIX obrigatória, presente em todas as caixas Unix) e leia apenas 1 linha por vez na memória, assumindo que sua string de título esteja sempre em um única linha e nem
<title>
aparecem</title>
em outros contextos nessa linha e não aparecem juntos em outros contextos em outras linhas, tudo que você precisa é:O acima diz apenas "remova a string do título (
sub("<title>.*</title>","")
) e se a linha resultante estiver vazia (!NF
), não imprima (next
)".Para demonstrar, usando este arquivo de entrada criado a partir de exemplos nas perguntas e respostas dos OPs:
podemos ver as strings de título sendo removidas sem que linhas em branco sejam deixadas para trás e sem que o
<style>
recuo da linha subsequente seja alterado:A respeito de:
No primeiro script que você está usando,
\s
que é uma extensão GNU não POSIX para sed como abreviação[[:space:]]
e em ambos os scripts você está tentando corresponder a uma nova linha, mas sed lê cada linha de entrada, 1 linha por vez, em seu buffer para operação ativado para que não haja nova linha no buffer para sed corresponder ao seu regexp. Existem várias maneiras de lidar com isso no sed (GNU sed para-z
ler o arquivo inteiro na memória de uma só vez, ou alguma instrução sed para anexar linhas a um "espaço de espera", ou um bloco composto de ações baseado no resultado da substituição ), mas é mais claro, mais simples, mais eficiente e mais portátil usar apenas o awk.Uma solução que encontrei é usar a
-z
opção:Observe que atualmente é suportado
sed
apenas pelo GNU. (E como eu uso o macOS, que é fornecido com utilitários BSD, ainda estou procurando outra coisa.)editar: Para resolver o problema mencionado por Kusalananda, precisamos tornar
sed
a correspondência não gananciosa. Isso é possível usando o seguinte "hack":test2.html
:Você não precisa tomar cuidado com
</title>
isso.