2010-08-11 18 views
6

estoy usando¿Cómo usar awk para extraer un campo citado?

awk '{ printf "%s", $3 }' 

para extraer algunas campo de una línea de espacio delimitado. Por supuesto, obtengo resultados parciales cuando el campo está citado con espacios libres dentro. ¿Puede algún cuerpo sugerir una solución, por favor?

+0

muestra el formato de archivo de entrada ... y el resultado deseado! – ghostdog74

Respuesta

1

Esto es realmente bastante difícil. Se me ocurrió la siguiente secuencia de comandos awk que divide la línea manualmente y almacena todos los campos en una matriz.

{ 
    s = $0 
    i = 0 
    split("", a) 
    while ((m = match(s, /"[^"]*"/)) > 0) { 
     # Add all unquoted fields before this field 
     n = split(substr(s, 1, m - 1), t) 
     for (j = 1; j <= n; j++) 
      a[++i] = t[j] 
     # Add this quoted field 
     a[++i] = substr(s, RSTART + 1, RLENGTH - 2) 
     s = substr(s, RSTART + RLENGTH) 
     if (i >= 3) # We can stop once we have field 3 
      break 
    } 
    # Process the remaining unquoted fields after the last quoted field 
    n = split(s, t) 
    for (j = 1; j <= n; j++) 
     a[++i] = t[j] 
    print a[3] 
} 
+0

Es una solución bastante compleja. Si no hay un simple * uno línea * solución, iría por perl – mmonem

6

muestre su archivo de entrada y salida deseada la próxima vez. Para obtener campos citados,

$ cat file 
field1 field2 "field 3" field4 "field5" 

$ awk -F'"' '{for(i=2;i<=NF;i+=2) print $i}' file 
field 3 
field5 
+0

En realidad es el registro del servidor web Apache. Parece que awk no puede hacerlo fácilmente. – mmonem

+1

@mmonem Entonces esto podría ser útil: http://serverfault.com/questions/ 11028/do-you-have-any-useful-awk-and-grep-scripts-for-parsing-apache-logs – schot

1

Aquí hay una posible solución alternativa a este problema. Funciona al encontrar los campos que comienzan o terminan con comillas, y luego unirlos. Al final, actualiza los campos y NF, por lo que si coloca más patrones después del que realiza la fusión, puede procesar los campos (nuevos) utilizando todas las características normales de awk.

Creo que esto utiliza solo las funciones de POSIX awk y no depende de las extensiones de gawk, pero no estoy del todo seguro.

# This function joins the fields $start to $stop together with FS, shifting 
# subsequent fields down and updating NF. 
# 
function merge_fields(start, stop) { 
    #printf "Merge fields $%d to $%d\n", start, stop; 
    if (start >= stop) 
     return; 
    merged = ""; 
    for (i = start; i <= stop; i++) { 
     if (merged) 
      merged = merged OFS $i; 
     else 
      merged = $i; 
    } 
    $start = merged; 

    offs = stop - start; 
    for (i = start + 1; i <= NF; i++) { 
     #printf "$%d = $%d\n", i, i+offs; 
     $i = $(i + offs); 
    } 
    NF -= offs; 
} 

# Merge quoted fields together. 
{ 
    start = stop = 0; 
    for (i = 1; i <= NF; i++) { 
     if (match($i, /^"/)) 
      start = i; 
     if (match($i, /"$/)) 
      stop = i; 
     if (start && stop && stop > start) { 
      merge_fields(start, stop); 
      # Start again from the beginning. 
      i = 0; 
      start = stop = 0; 
     } 
    } 
} 

# This rule executes after the one above. It sees the fields after merging. 
{ 
    for (i = 1; i <= NF; i++) { 
     printf "Field %d: >>>%s<<<\n", i, $i; 
    } 
} 

En un archivo de entrada como:

thing "more things" "thing" "more things and stuff" 

que produce:

Field 1: >>>thing<<< 
Field 2: >>>"more things"<<< 
Field 3: >>>"thing"<<< 
Field 4: >>>"more things and stuff"<<< 
0

Si estás en busca de un campo específico, entonces

$ cat file 
field1 field2 "field 3" field4 "field5" 

awk -F"\"" '{print $2}' file 

obras. Divide el archivo por ", por lo que el segundo campo en el ejemplo anterior es el que desea.

Cuestiones relacionadas