Quiero eliminar una línea de un archivo que contiene un carácter en particular solo una vez, si está presente más de una vez o no está presente, entonces mantenga la línea en el archivo.
Por ejemplo:
DTHGTY
FGTHDC
HYTRHD
HTCCYD
JUTDYC
Aquí, el carácter que quiero eliminar es C
así, el comando debería eliminar líneas FGTHDC
y JUTDYC
porque tienen C
exactamente una vez.
¿Cómo puedo hacer esto usando sed
o awk
?
fuente
awk
separador de campo!awk 'BEGIN { print "FS={" FS"}","OFS={" OFS "}";} {printf "%d fields : ",NF; for (i=1;i<=NF;i++) {printf "{" $i "} ";}; print "" }'
y alimentarlo con algunas líneas, algunas con múltiples spces y otras comenzando con espacios)enfoque sed :
-i
la opción permite la modificación de archivos en el lugar/^[^C]*C[^C]*$/
- coincide con líneas que contienenC
solo una vezd
- eliminar líneas coincidentesfuente
Esto se puede hacer con
sed
:Código:
Resultados:
¿Cómo?
C
via/C.*C/p
C
vía/C/d
, esto incluye las líneas ya impresas en el paso 1fuente
Esto elimina las líneas con exactamente una aparición de C.
La expresión regular
[^C]
coincide con un carácter que no es C (o nueva línea), y el operador de repetición (también conocido como estrella de Kleene)*
especifica cero o más repeticiones de la expresión anterior.La salida predeterminada de
grep
(y la mayoría de las otras herramientas orientadas al texto) es la salida estándar; redirigir a un nuevo archivo y tal vez moverlo sobre el archivo original si eso es lo que desea. Se puede utilizar la misma expresión regularsed -i
para la edición in situ:(En algunas plataformas, especialmente * BSD, incluido macOS, la
-i
opción requiere un argumento, como-i ''
.)fuente
sed -i '/^[^C]*C[^C]*$/d' file
- Parece que fue publicado antes, ¿cómo crees que es el plagio?grep
respuesta, pero obviamente se extiende fácilmente a lased -i
variante. No vi su respuesta porque estaba buscandogrep
respuestas anteriores .-i
consed
y en lugar de redirigir a un archivo nuevo y reemplazar el original con que si lased
utilidad salió sin error.grep -vx '[^C]*C[^C]*'
grep
porque es más claro y más robusto (en particular,sed
tiene un código de salida menos informativo).La herramienta POSIX para ediciones guionadas de un archivo (en lugar de imprimir los contenidos modificados a la salida estándar) es
ex
.Por supuesto, puede usarlo
sed -i
si su versión de Sed lo admite, solo tenga en cuenta que no es portátil si está escribiendo un script destinado a ejecutarse en diferentes tipos de sistemas.David Foerster preguntó en los comentarios:
Respuesta: sí.
Para
printf
vs.echo
es una cuestión de portabilidad; ver ¿Por qué es printf mejor que echo? Y también es más fácil intercalar líneas nuevas entre comandos usandoprintf
.Para
printf ... | ex
vs.ex -c ...
, es una cuestión de manejo de errores. Para este comando específico no importaría, pero en general sí; por ejemplo, intenta poneren un guion Contraste con lo siguiente:
El primero colgará y esperará entrada; el segundo saldrá cuando el
ex
comando reciba EOF , por lo que el script continuará. Existen soluciones alternativas, comos///e
POSIX, pero no están especificadas. Prefiero usar el formulario portátil, que se muestra arriba.Para el
g
comando, debe haber una nueva línea al final, y prefiero usarprintf
para ajustar los comandos en lugar de incrustar una nueva línea entre comillas simples.fuente
printf
y noecho
o algo asíex -c COMMAND
?printf
vs.echo
(aunque generalmente prefieroecho
cuando el argumento está codificado) pero no lo he usadoex
ampliamente hasta ahora.Aquí hay un par de opciones con perl.
Como solo está haciendo coincidir un solo carácter, puede usar
tr/C//
(una traducción, sin reemplazos), para devolver el número de coincidencias deC
:En términos más generales, si desea hacer coincidir una cadena de caracteres múltiples o una expresión regular, puede usar esto:
Esto asigna las coincidencias de la expresión regular
/C/g
a una lista@m
e imprime líneas cuando la longitud de esa lista no lo es1
.El
-i
interruptor se puede agregar para editar "en el lugar".fuente
fuente
sed
,t #...
normalmente se ramificaría a la etiqueta llamada#...
en la mayoría de las otrassed
implementaciones.!b
es GNU sed ya que a la rama no le gusta nada excepto una etiqueta o una nueva línea después.b
,t
,:
,}
(yr file
,w file
...) no puede tener un comando después de ellos en la misma línea. También puede usar-e
opciones separadas .g
modificador.Para cualquiera que quiera
awk
específicamente, ofreceríaomita la línea si coincide con el patrón, imprímalo de lo contrario. En realidad no es necesario
{print}
, puede usar una//
impresión predeterminada, pero creo que está más claro.Mi primer pensamiento fue usar
egrep -v
con el mismo patrón, pero eso en realidad no responde a la pregunta planteada.fuente
{next}
? Simplemente digaawk '/pattern/ {next} 1'
y se imprimirán todas las líneas que no coincidan con el patrón. O, mejor,awk '!/pattern/'
imprimirlos directamente.!/pattern/
(que de alguna manera se me olvidó ) pero preferiría ver un autoexplicativo//{print}
que un críptico1
. Asuma la menor competencia y fluidez de la siguiente persona para mantener su código, de manera consistente con no hacerlo seriamente menos eficiente o efectivo.