Escape seqüências passadas como args para gawk não interpretado

5

Eu quero ser capaz de passar um argumento na linha de comando para gawk que é avaliado para seqüências de escape.

A questão:

$ gawk 'BEGIN { print ARGV[1]; }' '\t'
\t

Em vez disso, gostaria de obter um caractere de tabulação real.

Dos documentos gawk :

The escape sequences in the preceding list are always processed first, for both string constants and regexp constants. This happens very early, as soon as awk reads your program.

Como posso interpretar as fugas de caracteres nos argumentos da linha de comando?

A meta final é myscript.awk --sep '\t' , em que separador é uma string de formato, portanto, passar uma tabulação literal não é uma opção. Eu também estou familiarizado com a maneira mais fácil de fazer isso no bash, mas estou interessado em uma maneira de fazer isso no awk.

    
por cdosborn 07.06.2015 / 10:06

3 respostas

0

A solução é usar getline .

Dentro de um arquivo:

BEGIN { 
    sep = ARGV[1]
    gsub(/'/, "'\''", sep);
    gsub(/%/, "%%", sep);
    "printf -- '" sep "'" | getline sep; 
    printf sep;
}
    
por 07.06.2015 / 18:58
2

How can I print the unescaped version of command line args?

print ARGV[1]

O problema é que você não quer o argumento da linha de comando sem escape. Você quer interpretar isso. Você está passando \t (a barra invertida de duas letras, T minúscula) e deseja que isso seja traduzido para uma barra invertida. Você precisará fazer isso manualmente. Simplesmente traduzir \t para uma tabulação é fácil - gsub(/\t/, "\t") - mas se você quiser também suportar escudos octal, e remover barra invertida antes de um caracter não reconhecido, isso é complicado no awk.

split ARGV[1], a, "\";
s = a[1]; delete a[1];
for (x in a) {
    if (skip_next) {
        skip_next = 0;
    } else if (x == "") {
        s = s "\";
        skip_next = 1;
    } else if (x ~ /^[0-7][0-7][0-7]/) {
        s = s sprintf("%c", 64*substr(x,1,1) + 8*substr(x,2,1) + substr(x,3,1));
        sub(/^.../, x);
    } else if (x ~ /^[0-7][0-7]/) {
        s = s sprintf("%c", 0 + 8*substr(x,1,1) + substr(x,2,1));
        sub(/^../, x);
    } else if (x ~ /^[0-7]/) {
        s = s sprintf("%c", 0 + substr(x,1,1));
        sub(/^./, x);
    } else {
        sub(/^a/, "\a", x) ||
        sub(/^b/, "\b", x) ||
        sub(/^n/, "\n", x) ||
        sub(/^r/, "\r", x) ||
        sub(/^t/, "\t", x) ||
        sub(/^v/, "\v", x);
    }
    s = s x;
}

(Atenção: código não testado!) Ao invés deste código complexo, você poderia invocar printf em uma sub-tampa. Mesmo isso não é tão fácil de fazer quando a string pode ser multilinha.

s = ARGV[1]
gsub(/'/, "'\''", s)
cmd = "printf %b '" s "'."
s = ""
while ((cmd | getline line) > 0) s = s line "\n"
sub(/..$/, "", s)

Observe que quando você escreve "\t" em um script awk, é uma string que contém o caractere de tabulação. É a maneira como a sintaxe do awk é: a barra invertida tem um significado especial em um literal de string. Nota: em um string literal , não em uma string . Se uma string contiver uma barra invertida, isso é apenas outro caractere. O fragmento de código-fonte "\t" , composto por quatro caracteres, é uma expressão cujo valor é a cadeia de um caractere que contém uma guia, da mesma forma que o fragmento de código-fonte 2+2 , composto por três caracteres, é uma expressão value é o número 4 .

Seria melhor que o seu script awk considerasse o argumento separador como uma string literal. Isso facilitaria o uso: sua interface exige que o chamador escape das barras invertidas no argumento. Se você quiser que o separador seja uma guia, passe um caractere de tabulação real.

    
por 08.06.2015 / 03:40
1

Primeiro de tudo, você não está realmente passando uma tabulação para o seu awk . Lembre-se de que o shell avalia os argumentos antes de transferi-los para awk e '\t' nas cotações é avaliado como um literal \ seguido por um \t :

$ set -x
$ gawk 'BEGIN { print ARGV[1]; }' '\t'
+ gawk 'BEGIN { print ARGV[1]; }' '\t'
\t

Como você pode ver acima, você não está passando uma tabulação para gawk , então você dificilmente pode esperar que ele imprima um. Compare com a versão abaixo que não passa por uma guia:

$ gawk 'BEGIN { print ARGV[1]; }' "$(printf '\t')"
++ printf '\t'
+ gawk 'BEGIN { print ARGV[1]; }' ' '  ## note the tab
                         ## This line contains a printed tab

Como alternativa, você pode passar a tabulação como uma variável:

gawk -v t='\t' 'BEGIN {print t}'

Aqui, o '\t' está sendo expandido pelo awk, não pelo shell, portanto a guia é interpretada corretamente.

    
por 07.06.2015 / 12:03

Tags