Come posso rimuovere tutti i commenti da un file?


21

Ho un file con commenti:

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

Voglio solo stampare tutto il codice non commentato:

foo
bar
stuff
morestuff
evenmorestuff

Essere in grado di eliminare i commenti da un file è così importante ... Qual è un buon modo per farlo?


1
non puoi rimuovere parti di una linea con grep. puoi usare sed per questo
miracle173

2
Il tuo testo e il tuo esempio sono in contraddizione. Scrivi delle righe commentate, ma chiaramente dall'ultima riga intendi le parti delle linee. E quindi la prima riga con un commento viene eliminata, incluso EOL, e potrebbe essere il secondo secondo, ma non è chiaro in quanto questa è l'ultima riga. Si prega di riformulare 'righe commentate' per essere esatti e non chiarire i propri esempi.
Anthon,

5
prova ad usare awk -F\# '$1!="" { print $1 ;} '.
Archemar,

2
Come verrebbe echo '#' # output a #gestita una linea come ?
Kusalananda

3
@Questionmark Potrei essere intelligente, ma non sto scrivendo intelligente-a-shell-grammar-parser intelligente.
Kusalananda

Risposte:


40

Un modo per rimuovere tutti i commenti è usare grepcon l' -oopzione:

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

dove

  • -o: stampa solo la parte della riga corrispondente
  • primo ^: inizio della riga
  • [^#]*: qualsiasi carattere tranne #zero ripetuto o più volte

Si noti che anche le linee vuote verranno rimosse, ma rimarranno le linee con solo spazi.


2
Vorrei usaregrep -v '^#' file > newfilewithoutcomments
Basile Starynkevitch il

1
Va notato che questo NON è un metodo generale per gli script di shell, poiché ad esempio la riga somvar='I am a long complicated string ## with special characters' # and I am a commentnon verrà gestita correttamente.
Wildcard il

Questa variante funziona meglio per me (su un Mac):grep -o '^[^#].*' file
Pierz,

I commenti sono spariti ma vedo un mucchio di spazi bianchi al loro posto nell'output? sedla soluzione ha solo una riga vuota, sembra un argomento valido per usare un'altra risposta, a meno che non mi manchi qualcosa?
JBallin,

@JBallin Hai forse definito un alias grepforse? Prova a cambiarlo grepin command grep, se vedi ancora spazi pubblicare l'input di esempio.
Jimmij,

31

Credo che sedpossa fare un lavoro molto migliore di questo grep. Qualcosa come questo:

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

Spiegazione

  • sedguarderà di default il tuo file riga per riga e stamperà ogni riga dopo aver eventualmente applicato le trasformazioni tra virgolette. ( sed '' your_filestamperà tutte le righe invariate).
  • Qui diamo seddue comandi da eseguire su ogni riga (sono separati da un punto e virgola).
  • Il primo comando dice: /^[[:blank:]]*#/d. In inglese, ciò significa che se la riga corrisponde a un hash all'inizio (preceduto da un numero qualsiasi di spazi iniziali), eliminare quella riga (non verrà stampata).
  • Il secondo comando è: s/#.*//. In inglese, cioè, sostituisci un segno di hash seguito da tutte le cose che riesci a trovare (fino alla fine della riga, cioè) con niente (niente è lo spazio vuoto tra gli ultimi due //).
  • In breve, questo scorrerà il tuo file eliminando le righe che consistono interamente in commenti e tutte le righe rimaste dopo che avranno i commenti cancellati da loro.

1
Eliminerà anche tutto ciò che viene trovato dopo un hash all'interno di una stringa , no? Ad esempio mystring="Hello I am a #hash" diventerà mystring="Hello I am a"
javadba il

@javadba, sì, ma a quel punto potresti anche usare un parser completo. Che cosa useranno questi dati in grado di comprendere virgolette e assegnazioni di variabili ma non possono gestire i commenti? (Ecco perché molti file di configurazione come crontabconsentono solo commenti a linea intera, con o senza spazi bianchi iniziali, ma non consentono commenti finali su una riga. La logica è MOLTO più semplice. Utilizzare solo la prima delle due istruzioni Sed in questa risposta per una spogliarellista di commento crontab.)
Wildcard

ottima risposta, questo sembra un ottimo equilibrio tra utilità e complessità per una vasta gamma di casi d'uso generali, ma nel caso in cui si sappia in anticipo che è necessario eliminare solo le righe che iniziano direttamente con #(nella colonna 1), c'è qualche vantaggio da sedsuperare grep -v "^#"?
RBF06,

4

È possibile ottenere l'output richiesto utilizzando il comando sed. Il comando qui sotto aveva fatto il trucco per me.

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

Dove

  • #.*$- Regexp filtrerà tutta la stringa che inizia #fino alla fine della riga

Qui abbiamo bisogno di rimuovere quelle linee così abbiamo sostituito con la parte 'sostituzione' vuota, saltando così.

  • g - menzione della ripetuta ricerca del modello fino al raggiungimento della fine del file.

Sintassi generale di sed: s/regexp/replacement/flags FileName


2
nota: la 4a riga sostituita con la nuova riga in questo caso.
αғsнιη,

1
Prova con uno script contenente quel sedcomando ...
Kusalananda

Non gestiràprint "#tag" # Print a hashtag.
Ray Butterworth il

3

Come altri hanno sottolineato, sed e altri strumenti basati su testo non funzioneranno bene se alcune parti di uno script sembrano commenti ma in realtà non lo sono. Ad esempio, potresti trovare un # all'interno di una stringa, o piuttosto comune $#e ${#param}.

Ho scritto un formattatore di shell chiamato shfmt , che ha una funzione per minimizzare il codice. Ciò include la rimozione di commenti, tra le altre cose:

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

Il parser e la stampante sono pacchetti Go, quindi se desideri una soluzione personalizzata, dovrebbe essere abbastanza facile scrivere un programma Go a 20 righe per rimuovere i commenti nel modo esatto che desideri.


2

Puoi usare la corrispondenza inversa in questo modo:

    #grep -v "#" filename

-v, --invert-match Inverte il senso della corrispondenza, per selezionare linee non corrispondenti. (-v è specificato da POSIX.)


2
@alinh Grazie per aver esaminato la risposta. Si noti che la domanda non richiede solo l'inizio della riga, ma in qualsiasi punto del file. Ciò sta dimostrando anche nel risultato atteso nella domanda sopra. La mia risposta sarebbe errata se cerco solo l'inizio della riga.
Raza,

zzz. mio male, non ho visto l'ultima riga :(
alinh

1
Ciò rimuoverà completamente la linea che inizia con evenmorestuffl'esempio del PO.
Joseph R.,

@JosephR. buona pesca. L'ho perso prima. In questo caso grep -o '^[^#]*' filesarebbe la soluzione migliore. questo è già spiegato da Jimmij. grazie per la tua recensione
Raza,

Non gestiràprint "#tag" # Print a hashtag.
Ray Butterworth il

2

Mi piace la risposta di joseph ma ne ho avuto bisogno per eliminare anche // commenti, quindi l'ho modificata leggermente e testata su Redhat

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

# example
cat SomeFile | nocom | less

Scommetto che c'è un modo migliore per rimuovere le righe vuote rispetto all'utilizzo delle stringhe, ma è stata la soluzione rapida e sporca che ho usato.

-Saluti


Non gestiràprint "#tag" # Print a hashtag.
Ray Butterworth il


1
cat YOUR_FILE | cut -d'#' -f1

Utilizza #come separatore di colonne e mantiene solo la prima colonna (che è tutto prima #).


1
Se YOUR_FILEè uno script che contiene quei comandi, lo script lascerebbe cat YOUR_FILE | cut -'nel file su quella riga.
Kusalananda

1

Usa espressione come

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

: -v: inverte la corrispondenza

: #: corrisponderà a tutte le righe che iniziano con #

: $ ^: corrisponderà a tutte le righe vuote


1
No, #corrisponderà in qualsiasi punto della riga e rimuoverà l'intera riga.
ilkkachu,

1

La soluzione migliore sarebbe usare il comando:

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

-I è la modifica sul posto ma il prefisso che segue direttamente indica a sed di creare un backup. In questo caso con un'estensione di data (ntp.conf.date) Eseguiamo due comandi ciascuno con uno spazio indirizzo, il primo elimina le righe commentate e il secondo, separato dal primo da un punto e virgola, elimina le righe vuote.

Ho trovato questa soluzione su: theurbanpenguin.com


0

Nessuna delle altre risposte sembra rendere giustizia, o lasciano le righe vuote o lasciano le righe in cui il commento non è al primo carattere. Ho finito per usare questo:

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

Questo imposta un alias, in modo che non sia necessario memorizzarlo (che è impossibile iniziare con). Apri una nuova sessione e avrai il nuovo nocomcomando. Allora puoi solo

nocom /etc/foobar.conf

Saluti.


1
non ha molto senso abbinare .*$la prima regex: l'ancoraggio non è utile e non stai catturando il testo corrispondente da usare in sostituzione. usare solo^\s*
Jeff Schaller

Non gestiràprint "#tag" # Print a hashtag.
Ray Butterworth il

0

Dopo la seconda risposta di Joseph R., aggiungo /^$/dper rimuovere la riga vuota.

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

-1

Sto postando ciò che funziona per me e sembra avere più senso, dopo aver letto gli altri, con una spiegazione. Un paio di post si sono avvicinati, ma non ho ancora potuto commentare (perché sono un newb):

grep -E -v "(^#.*|^$)" filename
  • -E = interpreta il seguente schema come un'espressione regolare, simile all'utilizzo di egrep
  • -v = stampa l'inversione del motivo (verranno stampate le linee che non corrispondono all'espressione)
  • "(^#.*|^$)"= questo ha una pipe che designa un'istruzione OR. Questa espressione dice di stampare qualsiasi riga che inizia con un #(e qualsiasi altra cosa dopo) O qualsiasi riga con zero caratteri tra l'inizio e la fine della riga.

Lo -vstamperà sullo schermo l'inversione di quello, che sarà qualsiasi riga con caratteri che non iniziano con a #.


Non gestiràprint "#tag" # Print a hashtag.
Ray Butterworth il

Ah, giusto ... certo. Grazie per la segnalazione. Stavo cercando una risposta per quanto riguarda i tipici file di configurazione di Linux, come pam.d configs, quindi non ci ho pensato. Immagino che dovrebbe essere adattato per trovare e rimuovere tutti i commenti che si trovano sulla stessa riga del codice. Ho appena visto probabilmente una soluzione migliore al mio problema particolare sopra: egrep -v "# | $ ^"
jackbmg
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.