Tengo una pregunta fácil. Tengo un archivo que contiene varias columnas y quiero filtros, usando awk.

De modo que la columna de interés es el 6 de columna y quiero encontrar a cada cadena que contiene :

  • comenzando con un número del 1 al 100
  • después de que una «S» o una «M»
  • de nuevo un número de 1 a 100
  • después de que una «S» o una «M»

Así por ejemplo : 20S50M es aceptar

He intentado :

awk '{ if($6 == '/[1-100][S|M][1-100][S|M]/') print} file.txt

pero no funcionó… ¿Qué estoy haciendo mal?

OriginalEl autor Nicolas Rosewick | 2013-09-23

5 Comentarios

  1. 35

    Esto debe hacer el truco:

    awk '$6~/^(([1-9]|[1-9][0-9]|100)[SM]){2}$/' file

    Regexplanation:

    ^                        # Match the start of the string
    (([1-9]|[1-9][0-9]|100)  # Match a single digit 1-9 or double digit 10-99 or 100
    [SM]                     # Character class matching the character S or M
    ){2}                     # Repeat everything in the parens twice
    $                        # Match the end of the string

    Que tiene unos cuantos problema con su declaración:

    awk '{ if($6 == '/[1-100][S|M][1-100][S|M]/') print} file.txt
    • == es la cadena de comparación operador. El regex comparación operador es ~.
    • No cita regex cadenas (nunca se cita nada con comillas simples en awk lado, el mismo script) y su guión está perdiendo al final (legal) sola cita.
    • [0-9] es el carácter de clase de la dígitos personajes, no es un intervalo numérico. Esto significa partido contra cualquier carácter en la clase 0,1,2,3,4,5,6,7,8,9 no cualquier valor numérico dentro de la gama de modo [1-100] no es la expresión regular para dígitos en el rango numérico de 1 a 100 pondría un 1 o un 0.
    • [SM] es equivalente a (S|M) lo que intentó [S|M] es el mismo que (S|\||M). Usted no necesita el operador O en una clase de caracteres.

    Awk utilizando la siguiente estructura condition{action}. Si la condición es Verdadera, la de las acciones en el siguiente bloque {} se ejecutan para el registro actual que se está leyendo. La condición en la que mi solución es $6~/^(([1-9]|[1-9][0-9]|100)[SM]){2}$/ que puede ser leído como la sexta columna coincide con la expresión regular, si es Cierto que la línea se imprime porque si usted no recibe ningún tipo de acciones, a continuación, awk ejecutará {print $0} por defecto.

    Muchas gracias eso es genial ! Sólo he último problema. Quiero añadir esto a un script en bash, pero la salida está vacío. Cuando me pruebe el comando en un shell, que funciona bien. Yo uso el comando awk en un tubo con la salida de un otro programa. comando | awk ‘$6~/^(|[0-3][ID]){2}(([7-9]|[1-9][0-9]|100)[SM])(|[0-3][ID]){2}(([7-9]|[1-9][0-9]|100)[SM])(|[0-3][ID]){2}$/’ > out.txt
    No hay absolutamente ninguna razón por la que awk script se comportan de manera diferente en un script de shell vs en la línea de comandos (suponiendo que la misma shell en ambos). Es posible que haya un fallo anterior en su secuencia de comandos de shell. Actualización de su pregunta para mostrar un copy/paste de lo que están haciendo en la línea de comandos y con el script de shell incluyendo y el contenido de la secuencia de comandos de shell para que podamos ayudarle a identificar el problema.
    Lo que @EdMorton dijo…
    +1 para el concepto de «regexplanation». Sé que el hilo de la nigromancia, pero estoy en lo profundo de un regex agujero por el momento y me hizo sonreír. 🙂

    OriginalEl autor Chris Seymour

  2. 2

    Yo haría el regex de verificación y el número de la validación de los diferentes pasos. Este código funciona con GNU awk:

    $ cat data
    a b c d e 132x123y
    a b c d e 123S12M
    a b c d e 12S23M
    a b c d e 12S23Mx

    Esperamos que sólo la 3ª fila para pasar la validación

    $ gawk '
        match($6, /^([[:digit:]]{1,3})[SM]([[:digit:]]{1,3})[SM]$/, m) && 
        1 <= m[1] && m[1] <= 100 && 
        1 <= m[2] && m[2] <= 100 {
            print
        }
    ' data
    a b c d e 12S23M

    Para el mantenimiento, se puede encapsular en una función:

    gawk '
        function validate6() {
            return( match($6, /^([[:digit:]]{1,3})[SM]([[:digit:]]{1,3})[SM]$/, m) && 
                    1<=m[1] && m[1]<=100 && 
                    1<=m[2] && m[2]<=100 );
        }
        validate6() {print}
    ' data
    +1 por el sólo fácilmente extensible solución hasta el momento si el OP se refiere a algo distinto de positive integer cuando dice number!

    OriginalEl autor glenn jackman

  3. 1

    Expresiones regulares no puede comprobar los valores numéricos. «Un número del 1 al 100» está fuera de lo que expresiones regulares puede hacer. Lo que puedes hacer es comprobar «1 a 3 dígitos.»

    Quieres algo como esto

    /\d{1,3}[SM]\d{1,3}[SM]/

    Tenga en cuenta que el carácter de clase [SM] no tiene la ! alternancia de caracteres. Sólo necesitaría que si estuviera escribiendo como (S|M).

    "A number from 1 to 100" is outside what regexes can do como un único carácter de clase no pueden, usar regex claro que puede.
    Lo que hice fue no comprobar el valor numérico. Su respuesta busca un 1 número de un dígito, o un 2-dígitos de número, o un literal de cadena 100. Que no es la comprobación de valor numérico. Sólo finge.
    Mi respuesta utiliza una expresión regular para validar dígitos en el rango de 1 a 100. Yo claramente esto en mi comentario que no se puede lograr con un solo carácter de clase y explicar la diferencia entre la clase de personaje y rangos numéricos en mi respuesta. La solución no está anclado, permite que los valores 0 y valor de más de 100 y no se compara contra el 6 campo.

    OriginalEl autor Andy Lester

  4. 1

    La manera de escribir la secuencia de comandos publicado:

    awk '{ if($6 == '/[1-100][S|M][1-100][S|M]/') print} file.txt

    en awk por lo que va a hacer lo que PARECEN estar tratando de hacer es:

    awk '$6 ~ /^(([1-9][0-9]?|100)[SM]){2}$/' file.txt

    Post algunas muestras de entrada y salida que se espera para ayudar a ayudar a usted más.

    OriginalEl autor Ed Morton

  5. 0

    Intente esto:

    awk ‘$6 ~/^([1-9]|0[1-9]|[1-9][0-9]|100)+[S|M]+([1-9]|0[1-9]|[1-9][0-9]|100)+[S|M]$/’ file.txt

    Porque no dicen exactamente cómo el formato será en la columna 6, el de arriba trabajará en donde la columna se ve como ’03M05S’, ’40S100M’, o ‘3M5S’; y excluir todo lo demás. Por ejemplo, no va a encontrar ’03F05S’, ‘200M05S’, ’03M005S, 003M05S, o ‘003M005S’.

    Si usted puede mantener los dígitos en la columna 6 de a dos cuando 0-99, o tres, cuando exactamente 100 – lo que significa exactamente un cero a la izquierda cuando menos de 10 años, y sin ceros a la izquierda de otra manera, se trata de una simple coincidencia. Usted puede utilizar el modelo anterior, pero excluyen los de un solo dígito (quitar la primera [1-9]), por ejemplo,

    awk ‘$6 ~/^(0[1-9]|[1-9][0-9]|100)+[S|M]+(0[1-9]|[1-9][0-9]|100)+[S|M]$/’ file.txt

    [S|M] significa either of the letters "S", "|", or "M". Hay un par más breve REs ya publicado que hacer el trabajo que el OP parece que quiere hacer.
    Ed – me contestó correctamente la pregunta. He utilizado su respuesta (que es una copia de Sudo_O) y no tiene salida. La pregunta no es sólo acerca de regexp, mucho más importante, se debe generar una salida con awk para responder a NicoBxl pregunta.
    Mi respuesta no es una copia de @sudo_O (leer de nuevo) y si no tienes salida, a continuación, su entrada es incorrecta o su awk no admite RE intervalos, en cuyo caso, obtener una nueva awk. Su respuesta es incorrecta, porque será la que coincida con las cadenas que no están en el formato deseado – excluyendo similares pero no las cadenas es siempre mucho más difícil para conseguir el correcto al escribir REs que simplemente la coincidencia de la deseada cadenas. Pruebe con una de $6 valor de 12|23| o incluso 12345678|98647329| en el archivo de entrada.
    Estoy en CentOS 6.4. Lo siento si las herramientas proporcionadas en que el sistema operativo no son nuevas suficiente para apoyar su respuesta. De nuevo, estoy tratando de ayudar a la persona a resolver un mundo real problema. Mirando como un ‘experto’ o ganando ASÍ puntos no es mi objetivo aquí. ¿Crear una entrada de prueba del archivo? Yo hice. Me encontré con su expresión y no funciona el uso de awk en CentOS 6.4 – no sin más esfuerzo para el cartel (usted) para ayudar a solucionar.
    de nuevo, si usted no puede conseguir mi solución a su trabajo y usted está seguro de que su entrada es correcta, entonces usted está usando un viejo y/o la versión rota de awk que no es ni siquiera POSIX. En serio, conseguir uno nuevo y se ahorrará más dolores de cabeza hacia abajo de la carretera. Si es una versión antigua de gawk, a continuación, por ahora, se podría agregar la --re-interval opción. Se publicó una solución que no funciona. He señalado que uno de los problemas con ella. No se ponga tan a la defensiva.

    OriginalEl autor Andrew

Dejar respuesta

Please enter your comment!
Please enter your name here