Como posso remover todos os comentários de um arquivo?

21

Eu tenho um arquivo com comentários:

foo
bar
stuff
#Do not show this...
morestuff
evenmorestuff#Or this

Eu só quero imprimir todo o código não comentado:

foo
bar
stuff
morestuff
evenmorestuff

Ser capaz de remover os comentários de um arquivo é tão importante ... Qual é uma boa maneira de fazer isso?

Ponto de interrogação
fonte
11
você não pode remover partes de uma linha com grep. você pode usar sed para este
miracle173
2
Seu texto e seu exemplo são contraditórios. Você escreve sobre as linhas que estão sendo comentadas, mas claramente da última linha você quer dizer partes da linha. E então a primeira linha com um comentário é excluída, incluindo a EOL, e a segunda segunda pode ser, mas não está claro, pois é a última linha. Redefina as linhas comentadas como exatas e desambigue seus exemplos.
Anthon
5
tente usar awk -F\# '$1!="" { print $1 ;} '.
Archemar 25/09
2
Como uma linha como echo '#' # output a #seria tratada?
Kusalananda
3
@ Questionmark Eu posso ser inteligente, mas não estou escrevendo um analisador de gramática-shell-gramatical.
Kusalananda

Respostas:

40

Uma maneira de remover todos os comentários é usar grepcom a -oopção:

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

Onde

  • -o: imprime apenas parte da linha correspondente
  • primeiro ^: começo da linha
  • [^#]*: qualquer caractere, exceto #repetidas zero ou mais vezes

Observe que as linhas vazias também serão removidas, mas as linhas com apenas espaços permanecerão.

jimmij
fonte
2
Eu usariagrep -v '^#' file > newfilewithoutcomments
Basile Starynkevitch
11
Deve-se notar que este NÃO é um método geral para scripts de shell, pois, por exemplo, a linha somvar='I am a long complicated string ## with special characters' # and I am a commentnão será tratada corretamente.
Curinga
Esta variante funciona melhor para mim (em um Mac):grep -o '^[^#].*' file
Pierz 8/18
Os comentários sumiram, mas estou vendo um monte de espaços em branco no lugar deles na saída? sedsolução tem apenas uma linha em branco, parece um argumento sólido para usar outra resposta, a menos que esteja faltando alguma coisa?
JBallin
@JBallin Você definiu alguns apelidos para greptalvez? Tente mudar greppara command grep, se você ainda vir espaços postar a entrada de amostra.
jimmij
31

Eu acredito que sedpode fazer um trabalho muito melhor disso do que grep. Algo assim:

sed '/^[[:blank:]]*#/d;s/#.*//' your_file

Explicação

  • sedpor padrão, examinará seu arquivo linha por linha e imprimirá cada linha após possivelmente aplicar as transformações entre aspas. ( sed '' your_fileapenas imprimirá todas as linhas inalteradas).
  • Aqui estamos dando seddois comandos para executar em cada linha (eles são separados por ponto e vírgula).
  • O primeiro comando diz: /^[[:blank:]]*#/d. Em inglês, isso significa que se a linha corresponder a um hash no início (precedida por qualquer número de espaços em branco à esquerda), exclua essa linha (ela não será impressa).
  • O segundo comando é: s/#.*//. Em inglês, substitua uma marca de hash seguida de tantas coisas quanto você puder encontrar (até o final da linha) por nada (nada é o espaço vazio entre as duas últimas //).
  • Em resumo, isso percorrerá as linhas de exclusão de arquivos que consistem inteiramente em comentários, e as linhas deixadas depois disso terão os comentários removidos.
Joseph R.
fonte
11
Ele também excluirá qualquer coisa encontrada após um hash dentro de uma string , não? Por exemplo, mystring="Hello I am a #hash" se tornará mystring="Hello I am a"
javadba 12/0317
@ javadba, sim, mas nesse ponto você também pode usar um analisador completo. O que vai usar esses dados que podem entender aspas e atribuições variáveis, mas não podem lidar com comentários? (É por isso que muitos arquivos de configuração, como crontabapenas permitem comentários de linha completa, com ou sem espaço em branco à esquerda, mas não permitem comentários finais em uma linha. A lógica é MUITO mais simples. Use apenas a primeira das duas instruções Sed nesta resposta para um stripper de comentário do crontab.)
Wildcard
ótima resposta, isso parece um ótimo equilíbrio de utilidade versus complexidade para uma ampla variedade de casos de uso gerais, mas no caso de você saber antecipadamente que só precisa excluir linhas começando diretamente por #(na coluna 1), existe algum benefício a sedmais grep -v "^#"?
RBF06 15/01
4

Você pode obter a saída necessária usando o comando sed. O comando abaixo havia feito o truque para mim.

sed 's/#.*$//g' FileName

Onde

  • #.*$- Regexp filtrará toda a sequência que começa com #até o final da linha

Aqui, precisamos remover essas linhas e substituí-las por vazias, para pular a peça de "substituição".

  • g - mencionando a pesquisa repetida do padrão até o final do arquivo.

Sintaxe geral de sed: s/regexp/replacement/flags FileName

Sridhar DD
fonte
2
nota: quarta linha substituída por nova linha neste caso.
αғsнιη
11
Tente isso com um script que contenha esse sedcomando ...
Kusalananda
Não vai aguentarprint "#tag" # Print a hashtag.
Ray Butterworth
3

Como outros já apontaram, o sed e outras ferramentas baseadas em texto não funcionarão bem se alguma parte do script se parecer com comentários, mas na verdade não for. Por exemplo, você pode encontrar um # dentro de uma string, ou o bastante comum $#e ${#param}.

Eu escrevi um formatador de shell chamado shfmt , que possui um recurso para reduzir o código. Isso inclui remover comentários, entre outras coisas:

$ cat foo.sh
echo $# # inline comment
# lone comment
echo '# this is not a comment'
[mvdan@carbon:12] [0] [/home/mvdan]
$ shfmt -mn foo.sh
echo $#
echo '# this is not a comment'

O analisador e a impressora são pacotes Go, portanto, se você deseja uma solução personalizada, deve ser bastante fácil escrever um programa Go de 20 linhas para remover os comentários da maneira exata desejada.

Daniel
fonte
2

Você pode usar a correspondência invertida assim:

    #grep -v "#" filename

-v, --invert-match Inverte a sensação de correspondência, para selecionar linhas não correspondentes. (-v é especificado pelo POSIX.)

Raza
fonte
2
@alinh Obrigado por revisar a resposta. Observe que a pergunta exigia não apenas o início da linha, mas qualquer parte do arquivo. Isso também está sendo mostrado no resultado esperado na pergunta acima. Minha resposta estaria incorreta se eu apenas procurasse o início da linha.
Raza
zzz. meu mal, não vi a última linha :(
alinh 25/09
11
Isso removerá completamente a linha que começa evenmorestuffno exemplo do OP.
Joseph R.
@JosephR. boa pegada. Eu senti falta disso antes. Nesse caso, grep -o '^[^#]*' fileseria a melhor solução. isso já é explicado por jimmij. obrigado pela sua revisão
Raza
Não vai aguentarprint "#tag" # Print a hashtag.
Ray Butterworth
2

Eu gosto da resposta de Joseph, mas precisava dela para remover // os comentários também, então eu a modifiquei um pouco e testei no redhat

# no comments alias
alias nocom="sed -E '/^[[:blank:]]*(\/\/|#)/d;s/#.*//' | strings"

# example
cat SomeFile | nocom | less

Aposto que há uma maneira melhor de remover linhas em branco do que usar strings, mas foi a solução rápida e suja que usei.

-Felicidades

brandon
fonte
Não vai aguentarprint "#tag" # Print a hashtag.
Ray Butterworth
2

Isso funcionou para mim

sed -i.old -E  "/^(#.*)$/d" file 
David Okwii
fonte
Não vai aguentarprint "#tag" # Print a hashtag.
Ray Butterworth
1
cat YOUR_FILE | cut -d'#' -f1

Ele usa #como separador de colunas e mantém apenas a primeira coluna (isso é tudo antes #).

Alexey
fonte
11
Se YOUR_FILEfor um script que contenha esses comandos, o script será deixado cat YOUR_FILE | cut -'no arquivo nessa linha.
Kusalananda
1

Use expressão como

egrep -v "#|$^" <file-name> 

: -v: fará correspondência invertida

: #: corresponderá a todas as linhas começando com #

: $ ^: corresponderá a todas as linhas em branco

aditya
fonte
11
Não, o #item corresponderá a qualquer lugar da linha e removerá a linha inteira.
Ilkkachu 09/10/19
1

A melhor solução seria usar o comando:

sed -i.$(date +%F) '/^#/d;/^$/d' ntp.conf

O -i é a edição no local, mas o prefixo diretamente a seguir informa ao sed para criar um backup. Nesse caso, com uma extensão de data (ntp.conf.date). Executamos dois comandos, cada um com um espaço de endereço, o primeiro exclui as linhas comentadas e o segundo, separado do primeiro por ponto e vírgula, exclui as linhas em branco.

Encontrei esta solução em: theurbanpenguin.com

jyoti
fonte
0

Nenhuma das outras respostas parece fazer essa justiça, elas deixam em linhas vazias ou em linhas onde o comentário não está no primeiro caractere. Acabei usando isso:

cat << EOF >> ~/.bashrc
alias nocom='sed -e "/^\s*#/d" -e "/^\s*$/d"'
EOF

Isso configura um alias, para que você não precise memorizá-lo (o que é impossível para começar). Abra uma nova sessão e você terá o novo nocomcomando. Então você pode apenas

nocom /etc/foobar.conf

Felicidades.

bviktor
fonte
11
não há muito sentido em corresponder .*$no primeiro regex - a âncora não é útil e você não está capturando o texto correspondente para usar em uma substituição. use just^\s*
Jeff Schaller
Não vai aguentarprint "#tag" # Print a hashtag.
Ray Butterworth
0

Após a 2ª resposta de Joseph R., adiciono /^$/dpara remover a linha em branco.

sed '/^[[:blank:]]*#/d;s/#.*//;/^$/d'
Pierre-Damien
fonte
-1

Estou postando o que funciona para mim e parece fazer mais sentido, depois de ler os outros, com explicações. Algumas postagens chegaram perto, mas ainda não pude comentar (porque sou novato):

grep -E -v "(^#.*|^$)" filename
  • -E = interpreta o seguinte padrão como uma expressão regular, semelhante ao uso do egrep
  • -v = imprime a inversão do padrão (as linhas que não correspondem à expressão serão impressas)
  • "(^#.*|^$)"= isso possui um canal que designa uma instrução OR. Essa expressão diz para imprimir qualquer linha que comece com a #(e qualquer outra coisa depois dela) OU qualquer linha com zero caracteres entre o início e o final da linha.

O -vimprimirá na tela a inversão disso, que será qualquer linha com caracteres que não comece com a #.

jackbmg
fonte
Não vai aguentarprint "#tag" # Print a hashtag.
Ray Butterworth
Ah, certo ... claro. Obrigado por apontar isso. Eu estava procurando uma resposta com relação aos arquivos de configuração típicos do Linux, como pam.d configs, então não pensei nisso. Eu acho que teria que ser adaptado para encontrar e remover qualquer comentário que esteja na mesma linha do código. Acabei de ver provavelmente uma solução melhor para o meu problema específico acima: egrep -v "# | $ ^"
jackbmg 28/10