Como remover todos os comentários de um arquivo que preserva caracteres hash com escape

6

Eu sei que isso foi perguntado antes, mas isso é um pouco diferente: eu preciso remover todos os comentários, excluindo escape # ou de outra forma não significava como começar um comentário (entre um ou dois apices)

Começando com o seguinte texto:

test
# comment
comment on midline # comment
escaped hash "\# this is an escaped hash"
escaped hash "\# this is not a comment"
not a comment "# this is not a comment - double apices"
not a comment '# this is not a comment - single apices'
this is a comment \# this is a comment
this is not a comment \# this is not a comment

Eu gostaria de obter

test
comment on midline
escaped hash "\# this is an escaped hash"
escaped hash "\# this is not a comment"
not a comment "# this is not a comment - double apices"
not a comment '# this is not a comment - single apices'
this is a comment \
this is not a comment \# this is not a comment

Eu tentei

grep -o '^[^#]*' file

mas isso também exclui hashes com escape.

OBSERVAÇÃO: o texto em que estou trabalhando escapou de # ( \# ), mas ele não possui escape duplo # ( \# ), portanto, não importa se eles são mantidos ou não. Eu acho que é mais legal para excluí-los, porque na verdade o hash não é escapado.

    
por Mike L'Angelo 06.05.2016 / 15:20

3 respostas

5

Com sed , você pode excluir as linhas que começam com # (precedidas por zero ou mais espaços em branco) e remover todas as strings que começam com # e não seguem uma única barra invertida (e somente se não forem entre aspas 1 ):

sed '/^[[:blank:]]*#/d
/["'\''].*#.*["'\'']/!{
s/\\#.*/\\/
s/\([^\]\)#.*//
}' infile

1: esta solução assume um único par de citações em uma linha

    
por 06.05.2016 / 15:29
2

Este é um problema mais complicado do que parece, mas não além a capacidade de regex. Para analisá-lo: Uma linha inteira consiste em texto não comentado opcionalmente seguido por texto comentado. O que pode aparecem em texto não comentado:

  1. Qualquer caractere diferente de \ , # , ' , "
  2. \ seguido por qualquer caractere
  3. Uma string entre aspas, que começa e termina com " e pode conter
    • A) qualquer caractere diferente de \ ou "
    • B) \ seguido por qualquer caractere
  4. Uma string entre aspas, que começa e termina com ' e pode conter
    • qualquer caractere diferente de '

(A diferença no tratamento dos dois tipos de citações é baseada em como shells unix lidar com isso - ajustar a gosto)

Traduzindo isso diretamente para o regex, você quer:

s/^([non comment])[comment]$//
non comment = ([^\"'#]|\.|"([^\"]|\.)*"|'[^']*')*
              (11111111|222|3(AAAAAA|BBB)33|4444444)*
comment = #.*
Therefore
s/^(([^\"'#]|\.|"([^\"]|\.)*"|'[^']*')*)#.*$//

Para um sed regex, você precisa de mais barras invertidas, antes dos caracteres ( , | e ) :

s/^\(\([^\"'#]\|\.\|"\([^\"]\|\.\)*"\|'[^']*'\)*\)#.*$//

E o bash precisa de cotações adicionais:

sed 's/^\(\([^\"'\''#]\|\.\|"\([^\"]\|\.\)*"\|'\''[^'\'']*'\''\)*\)#.*$//'

EDIT: Eu não tinha percebido que grep -o existia até que eu vi a resposta do @StéphaneChazelas. O mesmo regex principal pode ser adaptado a essa abordagem, e egrep permite que você evite fazer a maioria das barras invertidas extras:

grep -Eo '^([^\"'\''#]|\.|"([^\"]|\.)*"|'\''[^'\'']*'\'')*'
grep -Eo "^([^\\\"'#]|\\.|\"([^\\\"]|\\.)*\"|'[^']*')*"

Ambos são idênticos em significado (e fortuitamente são do mesmo tamanho), são apenas diferentes abordagens para citar shell - eu pessoalmente prefiro a primeira abordagem porque citação simples é o único caractere que eu tenho que me preocupar, mas você pode ache o segundo mais legível, e ele se parece muito com o que você escreveria em outras linguagens de programação.

Uma ressalva é que o regex não sabe o que fazer com linhas que contém citações não correspondentes. Eles não corresponderão ao regex, portanto, o comando sed não removerá nada, enquanto o comando grep removerá tudo.

    
por 06.05.2016 / 19:38
0

Este comando deve funcionar.

sed -e '/^#/d;s/[^\/]#.*$//' <file-path>

    
por 06.05.2016 / 15:56