web-dev-qa-db-fra.com

Existe-t-il un moyen d'afficher uniquement les lignes non commentées dans un fichier texte / script?

Souvent, lorsque vous parcourez manuellement un fichier, il y a tellement de commentaires que vos yeux sont glacés et vous commencez à souhaiter qu'il y ait un moyen de le montrer pour n'afficher que les lignes qui n'ont pas de commentaires.

Existe-t-il un moyen d'ignorer les commentaires avec cat ou un autre outil? Je suppose qu'il existe un moyen et cela implique une expression régulière. Je veux juste l'afficher et ne pas supprimer les lignes ou autres.

Les commentaires sont sous forme de # et j'utilise zsh comme xterm.

21
shirish

Eh bien, cela dépend de ce que vous entendez par commentaires. Si seulement des lignes sans # puis un simple:

grep -v '#'

pourrait suffire (mais cela appellera des lignes comme echo '#' un commentaire). Si les lignes de commentaires sont des lignes début avec #, alors vous pourriez avoir besoin de:

grep -v '^#'

Et si les lignes de commentaire sont des lignes commençant par # après quelques espaces facultatifs, vous pouvez alors utiliser:

grep -v '^ *#'

Et si le format de commentaire est tout autre chose, cette réponse ne vous aidera pas.

18
Stephen Rauch

Le simple grepping ne pourra jamais supprimer tous les commentaires (ou les commentaires uniquement) car grep ne comprend pas la langue qu'il traverse. Pour comprendre ce qu'est un commentaire et ce qui ne l'est pas, vous avez besoin d'un lexer qui comprend cette langue particulière.

Il y a plusieurs réponses sur SO sur la façon de supprimer tous les commentaires de langages de programmation spécifiques. J'ajouterai deux exemples ici.

Pour [~ # ~] c [~ # ~] le réponse de Josh Lee fait valoir:

gcc -fpreprocessed -dD -E test.c

Qui exécute le préprocesseur mais conserve les macros.

Pour python la réponse de unutb (avec une petite adaptation par moi-même) écrit un petit lexer en utilisant 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()))

Vous pouvez ensuite en écrire un pour chaque langage de programmation et utiliser un cas. En supposant que le lexer python est appelé 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

Donnez un nom au script et ajoutez les lexers pour les langues dont vous avez besoin/utilisez . Cela devrait être une conception plus ou moins robuste pour la suppression des commentaires de différents types de fichiers. (Utiliser file au lieu d'un cas sur les noms de fichiers serait également plus robuste).

14
grochmal
grep -v "^#" your_file | grep -v "^$" | less

Supprimer les lignes commence par "#" et supprimer également les lignes vides, puis envoyer le résultat à less pour un meilleur affichage.

8
BOUKANDOURA Mhamed

Dans le cas de scripts bash, c'est possible via set -vn commande. -v indique à bash de passer en mode verbeux, où les commandes lues seront également imprimées. -n indique à bash de lire uniquement le fichier de script sans rien exécuter.

Exemple:

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

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

Comme vous pouvez le voir, il ignore les lignes commençant par #, mais les commentaires en ligne sont toujours imprimés. Ce n'est bien sûr pas idéal, mais au moins ne nécessite aucun outil externe tel que grep. Je ne connais pas de telles fonctionnalités dans d'autres langages de script

4
Sergiy Kolodyazhnyy

Comme mentionné dans les commentaires ci-dessus, le format des "commentaires" dans votre cas d'utilisation fait une différence. Pourtant, pour plusieurs cas, cela peut suffire, sans avoir à créer de script.

La solution:

La lecture de la question suggère que vous utilisez déjà grep pour rechercher les fichiers, alors faites-le passer par un autre grep; comme ça:

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

Ce qui n'est pas piégé:

Cela autorisera toujours les lignes ou qui ont un caractère "déclencheur" ailleurs dans la ligne, qui ont des commentaires à la fin, comme dans echo "Hello World" # another comment, ou faisant partie d'un commentaire sur plusieurs lignes (sauf comme indiqué dans l'explication ci-dessous.

Si cela est utilisé comme un post-filtre pour votre grep, ces limitations devraient être négligeables car la plupart des commentaires seront toujours filtrés et vous ne craindrez plus "que vos yeux brillent".

L'explication:

Il existe trois modèles, que vous pouvez modifier en fonction de votre cas d'utilisation si nécessaire. La première (?:^;) capture les lignes commençant par ; personnage. Doit être le premier, sans espace blanc. La deuxième catches lines that begin with the `/* ... */` comment style, with or without leading white space. The third capture les lignes, avec ou sans espaces blancs, qui commencent par #, //, ou *. Le * dans le dernier motif permet d'attraper la ligne à l'intérieur d'un commentaire sur plusieurs lignes dans le /* ... */ style où le style courant consiste à exécuter une colonne de * pour connecter la première et la dernière ligne ensemble. Par exemple:

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

Le (? ... ) la notation autour de chaque modèle en fait des modèles "non capturants", espérons-le pour augmenter la vitesse et réduire la consommation de ressources. Le -Pv arguments pour grep lui dire d'utiliser les règles d'expressions régulières de Perl --Perl-regexp qui autorise le regroupement sans capture et autorise | opérateur d'alternance pour fonctionner, aucun des deux ne fonctionne dans grep CLI. La page de manuel de grep avertit que l'option -P est expérimentale, alors testez avant de vous y fier dans votre système. Le --invert-match indique à grep d'inverser la correspondance, renvoyant les lignes qui échouent au modèle. Ceux-ci peuvent être combinés et raccourcis à -vP au lieu.

La raison de l'utiliser comme post-filtre de votre grep normal est triple. Tout d'abord, vous pouvez effectuer votre grepping normal et n'ajouter le travail supplémentaire que lorsque vous rencontrez votre problème de trop de commentaires dans la sortie. (Moins de frappe et moins de ressources utilisées.) Deuxièmement, vous avez probablement déjà développé les modèles que vous utilisez couramment, et les habitudes qui vont avec, et leur ajouter plus de complexité pourrait les briser. Ajouter plus de travail aux modèles de débogage lorsque vous n'y êtes pas obligé est un travail inutile. Troisièmement, cela ne fonctionne pas du tout avec les commentaires sur plusieurs lignes, mais si vous avez déjà salué le fichier pour ce que vous voulez, il supprimera la plupart, sinon la totalité, des commentaires des résultats et servira votre objectif .

3
user207673

Voici un processus simple pour supprimer les commentaires, c'est-à-dire que tout vient après "#" en utilisant sed et 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"
2
Aljo Antony

Pour ce faire, pour bash (ou les fichiers Bourne Shell): vous pouvez profiter du "declare -f functionname" de bash, qui affiche le nom de la fonction avec à la fois une indentation appropriée ET des commentaires supprimés (afin que vos commentaires soient supprimés et en bonus) l'indentation serait bien aussi):

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
}

Ensuite, utilisez comme:

BEAUTIFIER script1.sh  script2.bash  etc

Attention: il supprimera tous les commentaires du script, même la première ligne "Shebang"! Vous pouvez également afficher la première ligne de $ f.

2
Olivier Dulac