¿Cómo puedo eliminar todos los comentarios de un archivo?

21

Tengo un archivo con comentarios:

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

Solo quiero imprimir todo el código no comentado:

foo
bar
stuff
morestuff
evenmorestuff

Poder quitar los comentarios de un archivo es muy importante ... ¿Cuál es una buena manera de hacerlo?

Questionmark
fuente
1
No puede eliminar partes de una línea con grep. puedes usar sed para esto
milagro173
2
Su texto y su ejemplo se contradicen. Escribes sobre las líneas que se comentan, pero claramente desde la última línea te refieres a las partes de la línea. Y luego se elimina la primera línea con un comentario, incluida EOL, y el segundo segundo puede ser, pero no está claro, ya que esa es la última línea. Reformule 'líneas comentadas' para ser exactos y desambigüe sus ejemplos.
Anthon
55
intenta usarlo awk -F\# '$1!="" { print $1 ;} '.
Archemar
2
¿Cómo se echo '#' # output a #manejaría una línea como ?
Kusalananda
3
@Questionmark Podría ser inteligente, pero no estoy escribiendo-a-shell-grammar-parser inteligente.
Kusalananda

Respuestas:

40

Una forma de eliminar todos los comentarios es usar grepcon la -oopción:

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

dónde

  • -o: imprime solo una parte coincidente de la línea
  • primero ^: comienzo de la línea
  • [^#]*: cualquier carácter excepto #cero repetido o más veces

Tenga en cuenta que las líneas vacías también se eliminarán, pero las líneas con solo espacios permanecerán.

jimmij
fuente
2
Yo usaríagrep -v '^#' file > newfilewithoutcomments
Basile Starynkevitch
1
Cabe señalar que este NO es un método general para los scripts de shell, ya que, por ejemplo, la línea somvar='I am a long complicated string ## with special characters' # and I am a commentno se manejará correctamente.
Comodín el
Esta variante funciona mejor para mí (en una Mac):grep -o '^[^#].*' file
Pierz
¿Los comentarios se han ido pero veo un montón de espacios en blanco en su lugar en la salida? sedla solución solo tiene una línea en blanco, parece un argumento sólido para usar otra respuesta, a menos que me falte algo?
JBallin
@JBallin ¿Definiste algún alias para grepquizás? Intente cambiar grepa command grep, si aún ve espacios, publique la entrada de muestra.
jimmij
31

Creo que sedpuede hacer un trabajo mucho mejor de esto que grep. Algo como esto:

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

Explicación

  • sedverá por defecto su archivo línea por línea e imprimirá cada línea después de aplicar posiblemente las transformaciones en las comillas. ( sed '' your_filesolo imprimirá todas las líneas sin cambios).
  • Aquí damos seddos comandos para ejecutar en cada línea (están separados por un punto y coma).
  • El primer comando dice: /^[[:blank:]]*#/d. En inglés, eso significa que si la línea coincide con un hash al principio (precedido por cualquier número de espacios en blanco iniciales), elimine esa línea (no se imprimirá).
  • El segundo comando es: s/#.*//. En inglés, es decir, sustituya una marca de hash seguida de tantas cosas como pueda encontrar (hasta el final de la línea, eso es) con nada (nada es el espacio vacío entre las dos últimas //).
  • En resumen, esto se ejecutará a través de su archivo eliminando líneas que consisten completamente en comentarios y cualquier línea que quede después de eso tendrá los comentarios eliminados de ellos.
Joseph R.
fuente
1
También eliminará todo lo que se encuentre después de un hash dentro de una cadena , ¿no? Por ejemplo, mystring="Hello I am a #hash" se convertirá en mystring="Hello I am a"
javadba
@javadba, sí, pero en ese momento también podrías usar un analizador completo. ¿Qué va a utilizar estos datos que pueden comprender citas y asignaciones variables pero no pueden manejar comentarios? (Esta es la razón por la cual muchos archivos de configuración, como crontabsolo permiten comentarios de línea completa, con o sin espacios en blanco iniciales, pero no permiten comentarios finales en una línea. La lógica es MUCHO más simple. Use solo la primera de las dos instrucciones Sed en esta respuesta para un separador de comentarios crontab.)
Comodín el
gran respuesta, esto parece un gran equilibrio entre utilidad y complejidad para una amplia gama de casos de uso generales, pero en el caso de que sepa de antemano que solo necesita eliminar líneas que comienzan directamente con #(en la columna 1), ¿Hay algún beneficio para sedmás grep -v "^#"?
RBF06
4

Puede lograr el resultado requerido utilizando el comando sed. El siguiente comando había hecho el truco para mí.

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

Dónde

  • #.*$- Regexp filtrará toda la cadena que comienza #hasta el final de la línea

Aquí necesitamos eliminar esas líneas, por lo que las reemplazamos por vacías, así que omitimos la parte de 'reemplazo'.

  • g - mencionando la búsqueda repetida del patrón hasta llegar al final del archivo.

Sintaxis general de sed: s/regexp/replacement/flags FileName

Sridhar DD
fuente
2
nota: cuarta línea reemplazada por una nueva línea en este caso.
αғsнιη
1
Pruebe eso con un script que contenga ese sedcomando ...
Kusalananda
No funcionaráprint "#tag" # Print a hashtag.
Ray Butterworth
3

Como otros han señalado, sed y otras herramientas basadas en texto no funcionarán bien si alguna parte de un script parece un comentario pero en realidad no lo es. Por ejemplo, podría encontrar un # dentro de una cadena, o el bastante común $#y ${#param}.

Escribí un formateador de shell llamado shfmt , que tiene una función para minificar el código. Eso incluye eliminar comentarios, entre otras cosas:

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

El analizador y la impresora son paquetes Go, por lo que si desea una solución personalizada, debería ser bastante fácil escribir un programa Go de 20 líneas para eliminar los comentarios de la manera exacta que desee.

Daniel
fuente
2

Puede usar la combinación invertida de esta manera:

    #grep -v "#" filename

-v, --invert-match Invierte el sentido de coincidencia, para seleccionar líneas no coincidentes. (-v es especificado por POSIX).

Raza
fuente
2
@alinh Gracias por revisar la respuesta. Tenga en cuenta que la pregunta no solo requiere el comienzo de la línea, sino también cualquier parte del archivo. Esto también se muestra en su resultado esperado en la pregunta anterior. Mi respuesta sería incorrecta si solo busco el comienzo de la línea.
Raza
zzz. mi mal, no vi la última línea :(
alinh
1
Esto eliminará por completo la línea que comienza evenmorestuffen el ejemplo del OP.
Joseph R.
@JosephR. buena atrapada. Me perdí eso antes. En este caso grep -o '^[^#]*' filesería la mejor solución. esto ya lo explica jimmij. gracias por tu comentario
Raza
No funcionaráprint "#tag" # Print a hashtag.
Ray Butterworth
2

Me gusta la respuesta de Joseph, pero también la necesitaba para quitar // comentarios, así que la modifiqué un poco y probé en redhat

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

# example
cat SomeFile | nocom | less

Apuesto a que hay una mejor manera de eliminar líneas en blanco que usar cadenas, pero fue la solución rápida y sucia que utilicé.

-salud

Brandon
fuente
No funcionaráprint "#tag" # Print a hashtag.
Ray Butterworth
2

Esto funciono para mi

sed -i.old -E  "/^(#.*)$/d" file 
David Okwii
fuente
No funcionaráprint "#tag" # Print a hashtag.
Ray Butterworth
1
cat YOUR_FILE | cut -d'#' -f1

Se utiliza #como separador de columnas y mantiene solo la primera columna (eso es todo antes #).

Alexey
fuente
1
Si YOUR_FILEes un script que contiene esos comandos, el script se dejaría cat YOUR_FILE | cut -'en el archivo en esa línea.
Kusalananda
1

Usa expresiones como

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

: -v: hará una inversión invertida

: #: coincidirá con todas las líneas que comienzan con #

: $ ^: coincidirá con todas las líneas en blanco

aditya
fuente
1
No, #coincidirá en cualquier lugar de la línea y eliminará toda la línea.
ilkkachu
1

La mejor solución sería usar el comando:

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

El -i es la edición in situ, pero el prefijo que sigue directamente le dice a sed que cree una copia de seguridad. En este caso con una extensión de fecha (ntp.conf.date) Ejecutamos dos comandos, cada uno con un espacio de direcciones, el primero elimina las líneas comentadas y el segundo, separado del primero por un punto y coma, elimina las líneas en blanco.

Encontré esta solución en: theurbanpenguin.com

jyoti
fuente
0

Ninguna de las otras respuestas parece hacerle justicia, ya sea que salen en líneas vacías o en líneas donde el comentario no está en el primer carácter. Terminé usando esto:

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

Esto configura un alias, para que no tenga que memorizarlo (lo cual es imposible comenzar). Abra una nueva sesión y tendrá el nuevo nocomcomando. Entonces puedes simplemente

nocom /etc/foobar.conf

Aclamaciones.

bviktor
fuente
1
no tiene mucho sentido coincidir .*$en la primera expresión regular: el ancla no es útil y no está capturando el texto coincidente para usarlo como reemplazo. use solo^\s*
Jeff Schaller
No funcionaráprint "#tag" # Print a hashtag.
Ray Butterworth
0

Después de la segunda respuesta de Joseph R., agrego /^$/dpara eliminar la línea en blanco.

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

Estoy publicando lo que funciona para mí y parece tener más sentido, después de leer los otros, con una explicación. Se acercaron un par de publicaciones, pero aún no podía comentar (porque soy un novato):

grep -E -v "(^#.*|^$)" filename
  • -E = interpretar el siguiente patrón como una expresión regular, similar a usar egrep
  • -v = imprime la inversión del patrón (se imprimirán las líneas que no coinciden con la expresión)
  • "(^#.*|^$)"= esto tiene una tubería que designa una instrucción OR. Esta expresión dice que imprima cualquier línea que comience con un #(y cualquier otra cosa después) O cualquier línea con cero caracteres entre el principio y el final de la línea.

El -vimprimirá en la pantalla la inversión de eso, que será cualquier línea con caracteres que no comience con a #.

jackbmg
fuente
No funcionaráprint "#tag" # Print a hashtag.
Ray Butterworth
Ah, claro ... por supuesto. Gracias por señalar eso. Estaba buscando una respuesta con respecto a los archivos de configuración de Linux típicos, como las configuraciones de pam.d, así que no pensé en eso. Supongo que tendría que adaptarse para encontrar y eliminar cualquier comentario que se encuentre en la misma línea que el código. Acabo de ver probablemente una mejor solución para mi problema particular anterior: egrep -v "# | $ ^"
jackbmg