Archivo de datos – data.txt:

ABC "I am ABC" 35 DESC
DEF "I am not ABC" 42 DESC

cat data.txt | awk '{print $2}'

tendrá como resultado el «yo» en lugar de la cadena ser citado,

Cómo hacer awk para que ignore el espacio dentro del presupuesto y de pensar que se trata de un único token?

InformationsquelleAutor Roy Chan | 2011-07-08

7 Comentarios

  1. 7

    Sí, esto se puede hacer muy bien en awk. Es fácil conseguir todos los campos sin graves hacks.

    (En este ejemplo funciona en ambos El Único Y Verdadero Awk y en boquiabiertos).

    {
      split($0, a, "\"")
      $2 = a[2]
      $3 = $(NF - 1)
      $4 = $NF
      print "and the fields are ", $1, "+", $2, "+", $3, "+", $4
    }
    • El formato de una sola línea: cat data.txt | awk 'split($0, a, "\"") {$2 = a[2]} {$3 = $(NF - 1)} {$4 = $NF} {print "and the fields are ", $1, "+", $2, "+", $3, "+", $4}'
    • Esto sólo funciona si usted tiene una sola citado campo, en la segunda posición, y tiene 4 campos en total. No es genérico. Una solución en la que está dispuesta a aceptar cualquier citado campo en cualquier posición será ideal.
  2. 8

    Otra alternativa sería el uso de la FPAT variable, que define una expresión regular que describe el contenido de cada campo.

    Guardar este script AWK como parse.awk:

    #!/bin/awk -f
    
    BEGIN {
      FPAT = "([^ ]+)|(\"[^\"]+\")"
    }
    {
      print $2
    }

    Hacerlo ejecutable con chmod +x ./parse.awk y analizar el archivo de datos como ./parse.awk data.txt:

    "I am ABC"
    "I am not ABC"
    • Gracias por el regex! 😉 Me salvó, al menos, 20 minutos de intentos frustrados. +1
    • Esto debe ser aceptado respuesta. Funciona como un encanto, gracias.
    • esta es la mejor respuesta, Para que pueda utilizar el siguiente comando para convertir los registros de mi para evitar el uso de FPAT cada vez: echo ‘filed1 «el segundo campo»‘ | awk ‘BEGIN {FPAT = «([^ ]+)|(\»[^\»]+\»)»}{for(i=1;i<=NF;i++){gsub(» «,»%20»,$i)} print}’
  3. 5

    Intente esto:

    $ cat data.txt | awk -F\" '{print $2}'
    I am ABC
    I am not ABC
    • Debo señalar que esto no es muy genérico, simplemente cambia el separador de campo a `» y selecciona el segundo campo.
    • Pero si quiero usar la información antes y después de… no funciona =(
    • Chan — verdadero. Awk es realmente no es la herramienta adecuada para el análisis de cadenas entre comillas. Ir hasta el tercer post en esta horriblemente formato de Caché de Google enlace y se puede ver un ejemplo de que es mucho más largo, pero podría ayudar.
    • No es tan difícil.
    • solución agradable; no lo había pensado de ese método.
  4. 3

    La respuesta para esta pregunta sólo funciona para las líneas con una sola citado campo. Cuando me encontré con esta pregunta que yo necesitaba algo que pudiera funcionar para un número arbitrario de los citados campos.

    Finalmente me encontré con una respuesta por Wintermute en otro hilo, y nos dio un buen generalizada solución a este problema. Sólo he modificado para quitar las comillas. Tenga en cuenta que usted necesita para invocar awk con -F\" cuando se ejecuta el siguiente programa.

    BEGIN { OFS = "" } {
        for (i = 1; i <= NF; i += 2) {
            gsub(/[ \t]+/, ",", $i)
        }
        print
    }

    Esto funciona mediante la observación de que cada elemento en la matriz, será dentro de las comillas cuando se separan por el «carácter, y por lo que reemplaza el espacio en blanco dividiendo las que no están en una cita con una coma.

    Usted puede fácilmente cadena de otra instancia de awk para hacer todo el procesamiento necesario (sólo tienes que utilizar el separador de campo interruptor de nuevo, -F,).

    Tenga en cuenta que este podría romperse si el primer campo es citado – yo no lo he probado. Si lo hace, sin embargo, debe ser fácil solución mediante la adición de una declaración de si empezar a las 2 en lugar de 1 si el primer carácter de la línea es un «.

  5. 2

    He estrujado juntos una función que re-divide $0 en una matriz llamada B. Espacios entre comillas dobles no actúan como separadores de campo. Funciona con cualquier número de campos, una mezcla de cotizados y no cotizados queridos. Aquí va:

    #!/usr/bin/gawk -f
    
    # Resplit $0 into array B. Spaces between double quotes are not separators.
    # Single quotes not handled. No escaping of double quotes.
    function resplit(       a, l, i, j, b, k, BNF) # all are local variables
    {
      l=split($0, a, "\"")
      BNF=0
      delete B
      for (i=1;i<=l;++i)
      {
        if (i % 2)
        {
          k=split(a[i], b)
          for (j=1;j<=k;++j)
            B[++BNF] = b[j]
        }
        else
        {
          B[++BNF] = "\""a[i]"\""
        }
      }
    }
    
    {
      resplit()
    
      for (i=1;i<=length(B);++i)
        print i ": " B[i]
    }

    Espero que ayude.

  6. 0

    Bueno, si quiere que todos los tres campos, se puede conseguir, pero se necesita una gran cantidad de tuberías:

    $ cat data.txt | awk -F\" '{print $1 "," $2 "," $3}' | awk -F' ,' '{print $1 "," $2}' | awk -F', ' '{print $1 "," $2}' | awk -F, '{print $1 "," $2 "," $3}'
    ABC,I am ABC,35
    DEF,I am not ABC,42

    Por la última tubería tienes todos los tres campos para hacer lo que quisiera.

    • En realidad, hay 4 campos.
    • Uy … me perdí en la presentación original.
  7. 0

    Aquí es algo parecido a lo que finalmente me puse a trabajar que es más genérico para mi proyecto.
    Nota: no usar awk.

    someText="ABC \"I am ABC\" 35 DESC '1 23' testing 456"
    putItemsInLines() {
        local items=""
        local firstItem="true"
        while test $# -gt 0; do
            if [ "$firstItem" == "true" ]; then
                items="$1"
                firstItem="false"
            else
                items="$items
    $1"
            fi
            shift
        done
        echo "$items"
    }
    
    count=0
    while read -r valueLine; do
        echo "$count: $valueLine"
        count=$(( $count + 1 ))
    done <<< "$(eval putItemsInLines $someText)"

    Que las salidas:

    0: ABC
    1: I am ABC
    2: 35
    3: DESC
    4: 1 23
    5: testing
    6: 456

Dejar respuesta

Please enter your comment!
Please enter your name here