Usa sed para encontrar y mantener solo las líneas con 2 caracteres alfabéticos en ellas

Tengo un file con muchas líneas como estas

33B87401 33B87402 33B87403 33B8EE44 33B87405 33B87406 33B87407 33B87408 33B87409 33B8740A 33B8740B 33B8740C 33B87D0D 33B8740E 33B8740F 33B87410 33B87411 33B87C1E 33B87CC3 33B87C1C 

Estoy buscando una manera de mantener solo las líneas que tienen solo 2 caracteres alfabéticos

salida para este ejemplo sería

 33B8740A 33B8740B 33B8740C 33B8740E 33B8740F 

aquí hay otra list

 8765C3E3 8765C3E4 8765C3E5 8765C3E6 8765C3E7 8765C3E8 8765C3E9 8765C3EA 8765C3EB 8765C3EC 8765C3ED 8765C3EE 8765C3EF 8765C3F0 

Lee muchos ejemplos de sed y awk y non puede reproducir esto.

Gracias

 sed -ne's/[[:alpha:]]//3;t' -e's//&/2p' <in >out 

s/// sustituirá la tercera ocurrencia en una línea de cualquier carácter en la class [[:alpha:]] . Posteriormente, se informa si esta sustitución fue exitosa y, de ser así, se ramifica fuera del script.

Debido a que sed es instruido -no para autoimprimir, las líneas de input con tres o más caracteres alfabéticos son en este punto efectivamente eliminadas de la salida, y las únicas líneas de input restantes para la statement de segunda s/// substitución son aquellas con dos o less caracteres alfabéticos .

La segunda sustitución usa // expresión regular vacía en el lado izquierdo – que, para sed , (más eficientemente) se refiere a la última compilation / regexp / – y entonces puede leerse como s/[[:alpha:]]/... una vez más. Este intenta s/// ubstituir la segunda ocurrencia de un carácter alfabético en una línea para & sí mismo – y como tal da como resultado un noop efectivo y no hay modificaciones reales en la línea. Sin embargo, si puede hacerlo con éxito, entonces la línea también se imprimirá en la salida.

En resumen, la primera s/// ubstitution elimina de forma efectiva de la salida todas las líneas de input que coinciden con tres o más caracteres alfabéticos, y las segundas impresiones de sustitución de lo que queda para dar salida solo a aquellas que coinciden con dos alfabéticos.

… w / grep

 grep -xE '([0-9]*[[:alpha:]]){2}' <in >out 

Esta afirmación no funciona exactamente como se pidió. Selecciona de input solo aquellas líneas que están compuestas solo de alfanuméricos, y de ese subset solo aquellos que coinciden con no más de dos alfabéticos, el segundo de los cuales debe ser el último carácter. Esta statement funcionará para producir el resultado deseado del ejemplo de la input de ejemplo.

Para hacer lo que se le preguntó, sin embargo:

 grep -xE '([^[:alpha:]]*[[:alpha:]]){2}[^[:alpha:]]*' 

Esa statement seleccionará las líneas de input que coinciden con no más de dos caracteres alfabéticos que se pueden encontrar en cualquier position de una línea de input, y que pueden estar separados por cualquier número de caracteres alfabéticos.

El interruptor grep 's -x se usa en ambos casos. Sin embargo, cualquiera de las instrucciones podría prescindir si los anclajes ^ head-of-line y $ tail-of-line fueran (pre | ap) añadidos a la expresión regular, respectivamente. El -x denota una coincidencia de línea completa, por lo que la expresión regular debe describir todas las líneas de input coincidentes por completo, de la cabeza a la queue.

Yo usaría perl :

 perl -ne 'print if length s/\d//gr == 2' 

Qué usos:

  • -n para envolver implícitamente un while ( <> ) { loop
  • s///r devuelve el text reemplazado, pero no modifica el original.
  • entonces eliminamos cualquier dígito, luego miremos la longitud de la string
  • e imprime la línea si eso es 2.

Nota: esto elimina los dígitos de sus líneas, sin dejar dígitos. Puede usar [^AZ] lugar.

O alternativamente, si es más claro:

 perl -ne 'print if (()=m/([AZ])/g) == 2' 

Esto funcionará con perl antiguo que no admite la bandera r . Utiliza la coincidencia de expresiones regulares para seleccionar text y count el número de elementos de la matriz (coincidencias). Y si eso es 2, imprime la línea.

Acabo de escribir un script de Python simple que hace exactamente lo que quiere, lo probé en su input, funciona bien.

  #!/usr/bin/python def count_letters(input): count=0 for char in input: if char.isalpha(): count += 1 return count fh=open('test_input','r') for line in fh.readlines(): if count_letters(line) == 2 : print line 

Algo en la línea:

grep '^[0-9]*[AF][0-9]*[AF][0-9]*$'

debería hacer el truco.

Esto significa que un patrón que comienza al principio de la línea, tiene algunos (tal vez no) dígitos, una letra, más dígitos, otra letra y más dígitos antes del final de la línea. Los anclajes son críticos, de lo contrario obtendrás todas las líneas con dos o más letras.

Con awk

 awk '{x=$0; gsub(/[^[:alpha:]]/, "", x)};length(x) == 2' file 

Esto establece cada línea en una variable x seguida de la sustitución de todos los caracteres no alfa dentro de x con la cadena vacía. Si la longitud del x así modificado es igual a 2 , la línea en cuestión califica

Alternativamente, con grep

 grep '^[^[:alpha:]]*[:[:alpha:]][^[:alpha:]]*[:[:alpha:]][^[:alpha:]]*$' file 

Con grep :

 LC_ALL=C grep -E '^([^[:upper:]]*[[:upper:]]){2}[^[:upper:]]*$' file.txt 

Ejemplo:

 % cat file.txt 33B87401 33B87402 33B87403 33B8EE44 33B87405 33B87406 33B87407 33B87408 33B87409 33B8740A 33B8740B 33B8740C 33B87D0D 33B8740E 33B8740F 33B87410 33B87411 33B87C1E 33B87CC3 33B87C1C % LC_ALL=C grep -E '^([^[:upper:]]*[[:upper:]]){2}[^[:upper:]]*$' file.txt 33B8740A 33B8740B 33B8740C 33B8740E 33B8740F