Comment supprimer tous les commentaires d'un fichier?

21

J'ai un dossier avec des commentaires:

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

Je veux juste imprimer tout le code non commenté:

foo
bar
stuff
morestuff
evenmorestuff

Pouvoir retirer des commentaires d'un fichier est si important ... Quelle est la bonne façon de le faire?

Point d'interrogation
la source
1
vous ne pouvez pas supprimer des parties d'une ligne avec grep. vous pouvez utiliser sed pour cela
miracle173
2
Votre texte et votre exemple se contredisent. Vous écrivez sur les lignes commentées, mais clairement à partir de la dernière ligne, vous voulez dire des parties de ligne. Et puis la première ligne avec un commentaire est supprimée, y compris EOL, et la deuxième seconde peut-être, mais ce n'est pas clair car c'est la dernière ligne. Veuillez reformuler «lignes commentées» pour être exact et lever l'ambiguïté de vos exemples.
Anthon
5
essayez d'utiliser awk -F\# '$1!="" { print $1 ;} '.
Archemar
2
Comment serait echo '#' # output a #gérée une ligne comme ?
Kusalananda
3
@Questionmark Je suis peut-être intelligent, mais je n'écris pas un interpréteur de grammaire-analyseur intelligent.
Kusalananda

Réponses:

40

Une façon de supprimer tous les commentaires est d'utiliser grepavec l' -ooption:

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

  • -o: imprime uniquement une partie correspondante de la ligne
  • premier ^: début de la ligne
  • [^#]*: tout caractère sauf #zéro ou plusieurs fois répété

Notez que les lignes vides seront également supprimées, mais les lignes avec uniquement des espaces resteront.

jimmij
la source
2
J'utiliseraisgrep -v '^#' file > newfilewithoutcomments
Basile Starynkevitch
1
Il convient de noter que ce n'est PAS une méthode générale pour les scripts shell, car par exemple la ligne somvar='I am a long complicated string ## with special characters' # and I am a commentne sera pas gérée correctement.
Wildcard
Cette variante fonctionne mieux pour moi (sur Mac):grep -o '^[^#].*' file
Pierz
Les commentaires ont disparu mais je vois un tas d'espace blanc à leur place dans la sortie? sedsolution n'a qu'une seule ligne vierge, semble être un argument solide pour utiliser une autre réponse, sauf si je manque quelque chose?
JBallin
@JBallin Avez-vous défini un alias pour greppeut-être? Essayez de passer grepà command grep, si vous voyez toujours des espaces après l'exemple d'entrée.
jimmij
31

Je crois que cela sedpeut faire un bien meilleur travail que cela grep. Quelque chose comme ça:

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

Explication

  • sedregardera par défaut votre fichier ligne par ligne et imprimera chaque ligne après avoir éventuellement appliqué les transformations dans les guillemets. ( sed '' your_fileaffichera simplement toutes les lignes inchangées).
  • Ici, nous donnons seddeux commandes à exécuter sur chaque ligne (elles sont séparées par un point-virgule).
  • La première commande dit: /^[[:blank:]]*#/d. En anglais, cela signifie que si la ligne correspond à un hachage à son début (précédé d'un nombre quelconque de blancs de début), supprimez cette ligne (elle ne sera pas imprimée).
  • La deuxième commande est la suivante : s/#.*//. En anglais c'est-à-dire, remplacez une marque de hachage suivie par autant de choses que vous pouvez trouver (jusqu'à la fin de la ligne, c'est-à-dire) par rien (rien n'est l'espace vide entre les deux derniers //).
  • En résumé, cela passera par votre fichier en supprimant les lignes qui se composent entièrement de commentaires et toutes les lignes restantes après cela auront les commentaires supprimés.
Joseph R.
la source
1
Il supprimera également tout ce qui a été trouvé après un hachage dans une chaîne , non? Par exemple mystring="Hello I am a #hash" , deviendra mystring="Hello I am a"
javadba
@javadba, oui, mais à ce stade, vous pourriez aussi bien utiliser un analyseur complet. Qu'est-ce qui va utiliser ces données qui peuvent comprendre les devis et les affectations de variables mais ne peuvent pas gérer les commentaires? (C'est pourquoi de nombreux fichiers de configuration tels crontabque n'autorisent que les commentaires de ligne complète, avec ou sans espace blanc de début, mais n'autorisent pas les commentaires de fin sur une ligne. La logique est BEAUCOUP plus simple. Utilisez uniquement la première des deux instructions Sed dans cette réponse. pour un décapant de commentaires crontab.)
Wildcard
excellente réponse, cela ressemble à un excellent équilibre entre l'utilité et la complexité pour un large éventail de cas d'utilisation généraux, mais dans le cas où vous savez à l'avance que vous n'avez qu'à supprimer les lignes commençant directement par #(dans la colonne 1), y a-t-il un avantage à sedplus grep -v "^#"?
RBF06
4

Vous pouvez obtenir la sortie requise à l'aide de la commande sed. La commande ci-dessous avait fait l'affaire pour moi.

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

  • #.*$- Regexp filtrera toute la chaîne qui commence #jusqu'à la fin de la ligne

Ici, nous devons supprimer ces lignes afin que nous les remplacions par des pièces vides afin de sauter le remplacement.

  • g - mentionner la recherche répétée du motif jusqu'à la fin du fichier.

Syntaxe générale de sed: s/regexp/replacement/flags FileName

Sridhar DD
la source
2
note: 4ème ligne remplacée par une nouvelle ligne dans ce cas.
αғsнιη
1
Essayez cela avec un script contenant cette sedcommande ...
Kusalananda
Ça ne marchera pasprint "#tag" # Print a hashtag.
Ray Butterworth
3

Comme d'autres l'ont souligné, sed et d'autres outils basés sur du texte ne fonctionneront pas bien si des parties d'un script ressemblent à des commentaires mais ne le sont pas. Par exemple, vous pourriez trouver un # à l'intérieur d'une chaîne, ou le plutôt commun $#et ${#param}.

J'ai écrit un formateur de shell appelé shfmt , qui a une fonctionnalité pour réduire le code. Cela comprend la suppression des commentaires, entre autres:

$ 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'

L'analyseur et l'imprimante sont des packages Go, donc si vous souhaitez une solution personnalisée, il devrait être assez facile d'écrire un programme Go de 20 lignes pour supprimer les commentaires exactement comme vous le souhaitez.

Daniel
la source
2

Vous pouvez utiliser une correspondance inversée comme ceci:

    #grep -v "#" filename

-v, --invert-match Inverse le sens de la correspondance, pour sélectionner les lignes non correspondantes. (-v est spécifié par POSIX.)

Raza
la source
2
@alinh Merci d'avoir examiné la réponse. Veuillez noter que la question nécessite non seulement le début de la ligne, mais n'importe où dans le fichier. Cela se voit également dans son résultat attendu dans la question ci-dessus. Ma réponse serait incorrecte si je ne cherche que le début de la ligne.
Raza
zzz. mon mauvais, n'a pas vu la dernière ligne :(
alinh
1
Cela supprimera complètement la ligne commençant par evenmorestuffdans l'exemple de l'OP.
Joseph R.
@JosephR. bonne prise. J'ai raté ça plus tôt. Dans ce cas, ce grep -o '^[^#]*' fileserait la meilleure solution. cela est déjà expliqué par jimmij. merci pour votre avis
Raza
Ça ne marchera pasprint "#tag" # Print a hashtag.
Ray Butterworth
2

J'aime la réponse de Joseph mais j'en avais besoin pour me déshabiller // commentaires aussi donc je l'ai légèrement modifiée et testée sur redhat

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

# example
cat SomeFile | nocom | less

Je parie qu'il y a une meilleure façon de supprimer les lignes vides que d'utiliser des chaînes, mais c'était la solution rapide et sale que j'ai utilisée.

-à votre santé

brandon
la source
Ça ne marchera pasprint "#tag" # Print a hashtag.
Ray Butterworth
2

Cela a fonctionné pour moi

sed -i.old -E  "/^(#.*)$/d" file 
David Okwii
la source
Ça ne marchera pasprint "#tag" # Print a hashtag.
Ray Butterworth
1
cat YOUR_FILE | cut -d'#' -f1

Il utilise #comme séparateur de colonnes et ne conserve que la première colonne (c'est tout avant #).

Alexey
la source
1
S'il YOUR_FILEs'agit d'un script contenant ces commandes, le script resterait cat YOUR_FILE | cut -'dans le fichier sur cette ligne.
Kusalananda
1

Utilisez une expression comme

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

: -v: fera une correspondance inversée

: #: correspondra à toutes les lignes commençant par #

: $ ^: correspondra à toutes les lignes vides

aditya
la source
1
Non, le #correspondra n'importe où sur la ligne et supprimera toute la ligne.
ilkkachu
1

La meilleure solution serait d'utiliser la commande:

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

Le -i est la modification sur place mais le préfixe suivant directement indique à sed de créer une sauvegarde. Dans ce cas avec une extension de date (ntp.conf.date) Nous exécutons deux commandes chacune avec un espace d'adressage, la première supprime les lignes commentées et la seconde, séparée de la première par un point-virgule, supprime les lignes vides.

J'ai trouvé cette solution sur: theurbanpenguin.com

jyoti
la source
0

Aucune des autres réponses ne semble rendre cette justice, soit elles laissent des lignes vides, soit des lignes où le commentaire n'est pas au premier caractère. J'ai fini par utiliser ceci:

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

Cela crée un alias, afin que vous n'ayez pas à le mémoriser (ce qui est impossible au départ). Ouvrez une nouvelle session et vous aurez la nouvelle nocomcommande. Ensuite, vous pouvez simplement

nocom /etc/foobar.conf

À votre santé.

bviktor
la source
1
il n'y a pas grand-chose à faire correspondre .*$dans le premier regex - l'ancre n'est pas utile et vous ne capturez pas le texte correspondant à utiliser dans un remplacement. utiliser juste^\s*
Jeff Schaller
Ça ne marchera pasprint "#tag" # Print a hashtag.
Ray Butterworth
0

Suite à la 2ème réponse de Joseph R., j'ajoute /^$/dpour supprimer la ligne vierge.

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

Je poste ce qui fonctionne pour moi et semble avoir le plus de sens, après avoir lu les autres, avec explication. Quelques articles sont venus près, mais je ne pouvais pas encore commenter (parce que je suis un nouveau):

grep -E -v "(^#.*|^$)" filename
  • -E = interpréter le modèle suivant comme une expression régulière, similaire à l'utilisation d'egrep
  • -v = imprimer l'inversion du motif (les lignes qui ne correspondent pas à l'expression seront imprimées)
  • "(^#.*|^$)"= ceci a un tube qui désigne une instruction OR. Cette expression indique d'imprimer toute ligne commençant par un #(et tout autre élément après) OU toute ligne de zéro caractère entre le début et la fin de la ligne.

Le -vva imprimer sur l'écran l'inversion de cela, qui sera n'importe quelle ligne avec des caractères qui ne commence pas par un #.

jackbmg
la source
Ça ne marchera pasprint "#tag" # Print a hashtag.
Ray Butterworth
Ah, c'est vrai ... bien sûr. Merci d'avoir fait remarquer cela. Je cherchais une réponse en ce qui concerne les fichiers de configuration linux typiques, tels que pam.d configs, donc je n'y ai pas pensé. Je suppose qu'il faudrait l'adapter pour trouver et supprimer tous les commentaires qui se trouvent sur la même ligne que le code. Je viens de voir probablement une meilleure solution à mon problème particulier ci-dessus: egrep -v "# | $ ^"
jackbmg