Tengo un archivo cuyo contenido es similar al siguiente.
0
0
0.2
0
0
0
0
Necesito eliminar todas las líneas con un solo cero.
Estaba pensando en usar grep -v "0"
, pero esto también elimina la línea que contiene 0.2. Vi que podía usar la -w
opción, pero esto tampoco parece funcionar.
¿Cómo puedo eliminar todas las líneas que contienen un solo 0 y mantener todas esas líneas que comienzan con un 0?
-w
, que falla aquí.grep
para esta tarea? ¿Y qué quieres decir exactamente con un solo cero ? Esto suena muy parecido a un problema XY .Respuestas:
De
man grep
:-w
falla porque el primero0
en0.02
se considera una "palabra", y por lo tanto se corresponde esta línea. Esto se debe a que es seguido por un carácter "sin palabra". Puede ver esto si ejecuta el comando original sin-v
, es decirgrep -w "0"
.fuente
-F
opción ya que no estamos usando patrones de expresiones regulares, solo coincidencias de cadenas simples-F
(sorprendentemente para mí) parece tomar una cantidad de tiempo similar o incluso un poco más lento (~ 5–10%). Por lo tanto, no estoy seguro de cuál sería la ventaja.grep
presumiblemente tiene un caso especial para expresiones regulares sin metacaracteres, porque ese es un caso de uso común. Es sorprendente quefgrep
sea más lento, pero no es sorprendente que la sobrecarga de notar este caso especial al compilar un patrón corto sea insignificante en comparación con el tiempo para escanear un archivo grande. (Si requiere un caso especial para ir tan rápido, contra un patrón con una clase de personaje ox.*y
.)grep
reconoce cualquier carácter que no sea\n
nueva línea como separador de línea. Si no, lo implícito^
y$
aún puede convertirse en una búsqueda de cadena fija comostrstr(big_buf, "\n0\n")
. (O0\n
al comienzo de un búfer). Pero no solo estamos buscando la primera coincidencia potencialmente lejos en un gran búfer, queremos filtrar eficientemente. Pero de todos modos, en teoría sí, es solo un memcmp de 2 bytes al comienzo de cada línea, y es de esperar que tanto fgrep como grep lo vean.Con grep:
^
significa el comienzo de la línea,$
significa el final de la línea.fuente
[a-Z0-9]
Si bien
grep
se puede usar para esto (como muestran claramente otras respuestas), demos un paso atrás y pensemos en lo que realmente quieres:Regex interpreta datos de secuencia de caracteres. No conocen los números, solo los dígitos individuales (y sus combinaciones regulares). Aunque en su caso particular hay un simple truco en torno a esta limitación, en última instancia es un desajuste de requisitos.
A menos que haya una muy buena razón para usar
grep
aquí (por ejemplo, porque lo ha medido y es mucho más eficiente, y la eficiencia es crucial en su caso), le recomiendo usar una herramienta diferente.awk
, por ejemplo, puede filtrar en base a comparaciones numéricas, por ejemplo:Pero también, para obtener todas las líneas que contienen números mayores que cero:
Me encanta la expresión regular, es una gran herramienta. Pero no es la única herramienta. Como dice el refrán, si todo lo que tienes es
grep
, todo parece un lenguaje normal.fuente
printf '0\n1\n-1\na\nb\n0\n0 also\n0.0\n-0.0\n0*0\n' | awk '($1 == 0)'
va a coincidir:0
,0.0
y-0.0
... y también0 also
! No solo "0". (que a veces es lo que se necesita, a veces no). Si el usuario solo quiere "0":awk '/^0$/'
(ogrep '^0$'
). También debe editar: el usuario debe agregar!
para negar la prueba, por lo que se oculta0
(y otros ceros) y muestra el resto. es decir:awk '!( $0 == 0)'
$1 == "0"
>
lugar de!=
(o, equivalentemente! (… == …)
) , para resaltar que esta es una comparación numérica arbitraria, no solo la igualdad. En cuanto a su otro comentario, esto es completamente cierto, pero luego estamos esencialmente de vuelta en el territorio de comparación de cadenas y la solución existente usandogrep
trabajos (aunque,awk
por supuesto, también funciona).$0=="0"
grep
's-w
es un poco enrevesado de una manera que divide la cadena original en componentes de palabras y no palabras (cualquier cosa excepto letras, dígitos o guiones bajos). Puesto que ya se ha encontrado con aa constituyente palabra válida0
en la0.02
que había afirmado la lógica de la negación para eliminar la línea.Usar
sed
es un poco fácil en este contexto para eliminar las palabras completas que coincidenfuente
Cuando las líneas que desea eliminar solo contienen un
0
seguido de la siguiente línea , puede seleccionar esas líneas emitiendo el siguiente comando:Esto solo imprimirá las ocurrencias
0
que se encuentran al final de una línea y al principio de una línea al mismo tiempo. La-v
opción luego invierte nuestra selección.fuente
-v
, por lo que no funciona.-v
opción, ¡gracias!grep -v "\b0\b"
grep -v "^0$"
-w funciona, pero en su caso 0.2 son dos palabras porque el carácter de punto es un separador de palabras.
fuente
grep -v "\b0\b"
Realmente no funciona aquí. ¿Qué versión de grep usas?grep (BSD grep) 2.5.1-FreeBSD
macOS ygrep (GNU grep) 2.16
ubuntu\<
y\>
como límites de palabras, pero eso tendrá el mismo efecto que-w
Otra respuesta por el bien de la variedad, suponiendo que tenga un PCRE habilitado
grep
Esto lleva a cabo una búsqueda anticipada negativa para que coincida con las líneas que comienzan
0
y no son seguidas por un punto. Luego-v
descarta las líneas que no coinciden. Puedes ver en acción aquífuente
0123
, que no es lo que el OP quiereSuponiendo que cualquier línea que no sea solo un 0 tenga un punto
grep '\.' file
fuente