No awk, como imprimir um intervalo de campos com os delimitadores originais de $ 0 intactos?

3

Como extrair uma substring de $ 0, em awk , quando a posição e duração dessa substring é baseada nas posições dos campos no original $ 0?

Ele efetivamente equivale a remover os primeiros campos n.lead e os últimos campos n.trail e todos os delimitadores iniciais e finais desses campos, do original $ 0

Aqui está um exemplo: Sabe-se apenas que o intervalo é de US $ 4 a US $ 8 inclusive. O delimitador é qualquer número de espaços e / ou uma única vírgula, por exemplo. " , " ou apenas "," ... e o delimitador principal deve ser ignorado.

          Input: "   a  a  a   X marks   the   start,   Y   marks the  end  "
Expected Output: "X marks   the   start,     Y"
    
por Peter.O 19.07.2011 / 03:34

3 respostas

2

O Awk não lembra as posições de campo ou as cadeias de caracteres do delimitador. Você terá que descobrir as posições de campo manualmente. Não é muito difícil.

echo "   a  b  c   X marks   the   start,   Y   marks the  end  " |
awk '{
    i=1; n=1; tmp=$0;  # i=field number, n=column number
    while (match(tmp, / *, *| +/)) {
        A[i]=n; B[i]=n+RSTART-1;     # A[i],B[i] = start,end of delimiter i
        ++i; n+=RSTART+RLENGTH-1;
        tmp=substr(tmp,RSTART+RLENGTH)
    }
    print substr($0, A[5], B[9]-A[5])   # start at 4+1 because the first field is empty
}'
    
por 19.07.2011 / 14:13
1

Isso pode ser uma solução, desde que não haja guias como delimitadores

#!/usr/bin/awk -f

  {
    start = index($0, " " $4 " ")
    stop  = index($0, " " $8 " ")
    print substr($0, start+1, stop - start + length($8))
  }
    
por 19.07.2011 / 07:32
1

Como está, ele funciona para dados com e sem um delimitador principal, mas falhará se algum campo contiver dados "sensíveis a regex". Uma solução alternativa é substituir pontos de regex. {Comprimento do campo} para cada campo ... Aqui está um link para essa versão ... É cludgey, mas não vai falhar por causa do problema acima mencionado:

awk 'BEGIN { FS = "([ \t]+)|([ \t]*,[ \t]*)" }
{ # Ignore leading delimiter, if present 
  hasLeadDlm = match($0, "^("FS")")
  LeadDlm = substr($0, 1, RLENGTH)
  if (hasLeadDlm) { sub("^("FS")", ""); }    # delete leading whitespace 
  sub("^"$1"("FS")"$2"("FS")"$3"("FS")", "") # delete leading fields
  match( $0, "^"$1"("FS")"$2"("FS")"$3"("FS")"$4"("FS")"$5)
  print substr($0, 1, RLENGTH)
}' <<< \
"a    X  a   X marks   the   start, ssY   marks the  end  
 a    X  a   X   marks the   start,  sY   marks the  end  
  a   X  a   X marks     the start,   Y   marks the  end  
   a  X  a   X marks   the     start ,Y   marks the  end  
    a   X  a   X marks   the   start,sssY   marks the  end"
    
por 19.07.2011 / 15:49