Existe uma maneira de mostrar apenas linhas não comentadas em um arquivo de texto / script? [duplicado]

17

Muitas vezes, ao passar manualmente por um arquivo, há tantos comentários que seus olhos passam e você começa a desejar que houvesse uma maneira de mostrar apenas as linhas que não têm comentários. / p>

Existe uma maneira de pular comentários com o gato ou outra ferramenta? Eu estou supondo que há um caminho e envolve uma expressão regular. Eu quero apenas para exibir e não realmente remover quaisquer linhas ou tal.

Os comentários estão na forma de # e estou usando zsh como meu xterm.

    
por shirish 17.01.2017 / 02:37

7 respostas

14

Bem, isso depende do que você quer dizer com comentários. Se apenas linhas sem um # , então um simples:

grep -v '#'

pode ser suficiente (mas isso chamará linhas como echo '#' um comentário). Se as linhas de comentário forem linhas iniciando com # , talvez seja necessário:

grep -v '^#'

E se as linhas de comentário forem linhas começando com # depois de algum espaço em branco opcional, você poderá usar:

grep -v '^ *#'

E se o formato do comentário for algo totalmente diferente, essa resposta não ajudará você.

    
por 17.01.2017 / 02:42
14

Apenas o grepping nunca será capaz de remover todos os comentários (ou apenas comentários) porque o grep não entende a língua que está passando. Para entender o que é um comentário e o que não é um, você precisa de um lexer que entenda esse idioma em particular.

Existem várias respostas ao SO sobre como remover todos os comentários de linguagens de programação específicas. Vou adicionar dois exemplos aqui.

Para C , a resposta de Josh Lee argumenta :

gcc -fpreprocessed -dD -E test.c

Que executa o pré-processador, mas mantém as macros.

Para python a resposta por unutbu (com uma pequena adaptação por mim) escreve um pequeno lexer usando tokenize:

import tokenize
import io
import sys

def nocomment(s):
    result = []
    g = tokenize.generate_tokens(io.BytesIO(s).readline)  
    for toknum, tokval, _, _, _  in g:
        # print(toknum,tokval)
        if toknum != tokenize.COMMENT:
            result.append((toknum, tokval))
    return tokenize.untokenize(result)

print(nocomment(sys.stdin.read()))

Você pode escrever um desses para cada linguagem de programação e usar um caso. Supondo que o léxico de python é chamado remove-comments.py

#!/bin/sh
case "$1" in
  *.py)
    remove-comments.py < "$1"
    break
    ;;
  *.c|*.C|*.cc)
    gcc -fpreprocessed -dD -E "$1"
    break
    ;;
  *)
    echo I do not know how to remove comments from $1, sorry
    break
    ;;
esac

Dê um nome ao script e adicione os lexers para os idiomas que você precisa / usa . Este deve ser um design mais ou menos robusto para a remoção de comentários de diferentes tipos de arquivo. (Usar file em vez de um caso em nomes de arquivos também seria mais robusto).

    
por 17.01.2017 / 03:26
6
grep -v "^#" your_file | grep -v "^$" | less

Remover as linhas começa com "#" e também remover as linhas vazias, do que enviar o resultado para less para uma melhor exibição.

    
por 17.01.2017 / 08:43
4

No caso de scripts bash , é possível usar o comando set -vn . -v diz ao bash para entrar no modo verboso, onde os comandos lidos também serão impressos. -n diz ao bash para ler apenas o arquivo de script sem executar nada.

Exemplo:

$ cat ./testscript.sh                                                                                                    
#!/bin/bash

# comment
set -vn
echo "Hello World" # another comment
$ ./testscript.sh                                                                                                        
echo "Hello World" # another comment

Como você pode ver, ele ignora as linhas que começam com # , mas os comentários em linha ainda são impressos. Isso obviamente não é o ideal, mas pelo menos não requer ferramentas externas como grep . Não estou ciente de tais recursos em outras linguagens de script

    
por 17.01.2017 / 03:10
3

Como mencionado nos comentários acima, o formato do 'comentário' no seu caso de uso faz a diferença. Ainda assim, para vários casos, isso pode ser suficiente, sem ter que criar um script.

A solução:

A leitura da pergunta sugere que você está usando grep para pesquisar os arquivos de qualquer maneira, então canalize isso por meio de outro grep ; assim:

grep your_pattern your_file | grep --perl-regexp --invert-match '(?:^;)|(?:^\s*/\*.*\*/)|(?:^\s*#|//|\*)'

O que não está preso:

Isso ainda permitirá linhas ou que tenham um caractere "acionador" em outro ponto da linha, que tenham comentários no final, como em echo "Hello World" # another comment ou que façam parte de um comentário em várias linhas (exceto conforme observado no explicação abaixo.

Se isso for usado como pós-filtro para o grep, essas limitações devem ser insignificantes, já que a maioria dos comentários ainda serão filtrados e você não se preocupará mais "com os olhos vidrados".

A Explicação:

Existem três padrões, que você pode modificar para se adequar ao seu caso de uso, se necessário. O primeiro (?:^;) captura as linhas que começam com o caractere ; . Deve ser o primeiro, sem espaço em branco. O segundo catches lines that begin with the '/* ... */' comment style, with or without leading white space. The third captura linhas, com ou sem espaço em branco inicial, que começam com # , // ou * . O * no último padrão ajuda a capturar a linha dentro de um comentário de várias linhas no estilo /* ... */ , em que o estilo comum deve executar uma coluna de * para conectar a primeira e a última linha juntas. Por exemplo:

/************
 *
 * This is my
 * multi-line
 * comment.
 *
 ************/

A notação (? ... ) em torno de cada padrão os torna padrões de 'não captura', com a esperança de aumentar a velocidade e reduzir o consumo de recursos. Os argumentos -Pv para o grep dizem para usar regras de expressão regular Perl --perl-regexp que permite o agrupamento sem captura e permite que o operador de alternância | funcione, nenhum dos quais funciona no CLP grep. A página man grep avisa que a opção -P é experimental, por isso teste antes de confiar no seu sistema. O --invert-match informa grep para reverter a correspondência, retornando linhas que falham no padrão. Estes podem ser combinados e encurtados para -vP .

O motivo para usar isso como um pós-filtro para seu grep é triplo. Primeiro, você pode fazer o seu grepping normal e adicionar apenas o trabalho extra de usar isso quando tiver problemas com muitos comentários na saída. (Menos digitação e menos recursos usados.) Segundo, você provavelmente já desenvolveu os padrões que você costuma usar, e os hábitos que os acompanham, adicionando mais complexidade a eles, podem quebrá-los. Adicionar mais trabalho para depurar padrões quando não é necessário é um trabalho perdido. Terceiro, Ele não combina bem com comentários de várias linhas, mas se você já tiver usado o arquivo para o que deseja, ele removerá a maioria, se não todos, os comentários dos resultados e atenderá a sua finalidade. .

    
por 17.01.2017 / 05:05
2

Para fazer isso no bash (ou nos arquivos shell da bourne): você pode tirar proveito do bash "declare -f functionname", que exibe functionname com o recuo adequado E com os comentários removidos (para que seus comentários sejam removidos e como bônus, o recuo também seria bom):

BEAUTIFIER () {
  for f in "$@"; do
    printf "%s" "
      F_from_sh () {
        $(cat "$f")
      }
      echo ___ beautified version of $f : _________________
      declare -f F_from_sh | awk ' (NR > 2) && length>2' | sed -e 's/^  //'
    " | bash
  done
}

Em seguida, use como:

BEAUTIFIER script1.sh  script2.bash  etc

Por favor note: que vai se livrar de todos os comentários do roteiro, até mesmo da primeira linha "shebang"! Você pode querer também exibir a primeira linha de $ f.

    
por 17.01.2017 / 11:26
2

Aqui está um processo simples para remover comentários, ou seja, tudo vem depois de '#' usando sed e awk.

[root@master]# cat hash
This is a program to remove comments from this file
#!/bin/bash
# comment
set -vn # comment
echo "Hello World" # another comment
echo "testscript for removing comments"
echo "Hello World" # another comment
echo 'This is a # sign' #comment
echo "This is a # sign" #comment

[root@master]# awk -F '#' 'BEGIN{OFS="#";} { if (!/#/) ;else $NF="";print $0}' hash | sed -n 's/#$//g;p'
This is a program to remove comments from this file
set -vn
echo "Hello World"
echo "testscript for removing comments"
echo "Hello World"
echo 'This is a # sign'
echo "This is a # sign"
    
por 17.01.2017 / 08:39