Como remover? xml em * início da linha * com sed?

3

Eu tenho um arquivo cuja primeira linha começa com <?xml

Eu posso removê-lo com sed usando

/<\?xml/d

mas se eu tentar garantir o início da linha -

/^<\?xml/d

não corresponde.
No entanto, outras linhas, como

<head ...

são removidos com

/^<head/d

Eu também tentei

/^\<\?xml/d

mas sem correspondência.

    
por Michael Durrant 15.09.2015 / 03:50

4 respostas

8

Uso:

sed '/^<?xml/d' filename

Sob o GNU sed, \? significa zero ou um dos caracteres anteriores. (No POSIX sed, \? é indefinido.) Como você deseja corresponder a um literal ? , deixe-o sem escape.

Exemplos

Vamos considerar este arquivo de teste:

$ cat filename
<?xml deleteme
<.xml keepme
..xml keepme

A solução acima produz o resultado desejado:

$ sed '/^<?xml/d' filename
<.xml keepme
..xml keepme

O primeiro comando na pergunta incorretamente não produz resultados:

$ sed '/<\?xml/d' filename
$

Isso ocorre porque corresponde a todas as linhas que contêm xml , opcionalmente precedidas por < . Como todas as linhas contêm xml , todas elas são excluídas.

O segundo comando não exclui nada:

$ sed '/^<\?xml/d' filename
<?xml deleteme
<.xml keepme
..xml keepme

Isso exclui qualquer linha que comece com zero ou um < seguido imediatamente por xml . Como as linhas sempre têm pelo menos um caractere entre < e xml , nenhuma linha é excluída.

Como escapar de caracteres quando em dúvida

Se você não tiver certeza se um caractere é regex ativo e deseja desativá-lo, a melhor coisa a fazer é colocá-lo entre colchetes:

$ sed '/^[<][?]xml/d' filename
<.xml keepme
..xml keepme

Dentro de [...] , todos os caracteres são tratados como caracteres literais.

    
por 15.09.2015 / 03:56
5

Em POSIX Expressão regular básica , o comportamento de \? é indefinido ( algumas outras seqüências de escape para o GNU sed são \| , \+ e mais aqui ).

O GNU sed usou o BRE por padrão e trata essas sequências de escape como caracteres especiais, significando que \? é o mesmo que ? , correspondendo zero ou um caractere.

Portanto, <\?xml significa zero ou um < seguido por xml , que corresponde a <?xml . Com o BRE, apenas ^ , $ , * , . , \ e [ são caracteres especiais , portanto, deixe todos os outros caracteres intocados se quiser corresponder literalmente

sed -e '/^<?xml/d' <file

Se você quiser manter a sequência com escape para corresponder à string literal, ative a Expressão regular estendida (que será tornar-se padrão POSIX na próxima versão ):

sed -E '/^\?xml/d' <file

( sed -E funciona com o BSD sed)

    
por 15.09.2015 / 04:54
2

I have a file whose first line starts with <?xml [...] if I try and ensure start of line /^<\?xml/d it doesn't match

É possível que o texto seja precedido por uma Marca de pedido de byte (BOM) . Estes são comuns em arquivos no formato UTF-16 (particularmente aqueles dos sistemas Windows) e são usados para indicar a endianness dos bytes que compõem os caracteres de 16 bits no arquivo.

Você pode verificar isso com uma das muitas ferramentas de despejo hexadecimal ( hex , hexdump , od -c para três) e examinando os primeiros caracteres. Se você vir FF FE ou FE FF como os dois primeiros caracteres, é uma lista de materiais.

Como provavelmente é melhor manter a lista de materiais no lugar, você conseguirá a solução da melhor maneira simplesmente removendo o requisito de início de linha do seu RE.

Por acaso, se você estiver tentando extrair dados de um arquivo XML, geralmente seria melhor analisá-los corretamente, em vez de pesquisá-los com REs. (Há exceções, é claro, mas estou falando sobre o caso geral, que permite a reformatação inesperada, mas válida, do arquivo, estruturas de comentários, etc.)

    
por 15.09.2015 / 10:16
1

Se isso for um resultado da transformação xml ( xsltprox foo.xsl bar.xml , por exemplo), a linha xml estará apenas na primeira linha.

Use:

awk 'NR>1' 

Quando em pipe ou:

awk 'FNR>1' file1 file2 ... > result

com vários arquivos.

 sed -i -e 1d file1 file2 ...
    
por 15.09.2015 / 06:27

Tags