Como posso fazer o awk no Busybox tratar a entrada inteira com caractere NULL entre como um único registro?

1

Eu escrevi um script de codificação de base64 para o meu sistema Busybox.

#!/bin/sh
base64encode()
{
/usr/bin/awk -- '
function asc(char,l_found)
{
        l_found=0;
        for (i=0;i<=255;i++){
        if (sprintf("%c",i)==char) l_found=i;
        }
        return l_found;
}

function base64_and(var,x,l_res,l_i)
{
        l_res=0;
        for (l_i=0;l_i<8;l_i++){
                if (var%2==1 && x%2==1) l_res=l_res/2+128;
                else l_res/=2;
                       var=int(var/2);
                x=int(x/2);
        }
        return l_res;
}

function base64_lshift(var,x)
{
        while(x>0){
        var*=2;
        x--;
        }
        return var;
}

function base64_rshift(var,x)
{
        while(x>0){
        var=int(var/2);
        x--;
        }
        return var;
}

BEGIN{
BASE64="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
result="";
}

{
        while (length($0)>0){
printf "Source: %s Length: %i\n",$0,length($0);
                if (length($0)==1){
                        byte1=asc(substr($0,1,1));
                        byte2=0;
                        byte3=0;
                }

                if (length($0)==2){
                        byte1=asc(substr($0,1,1));
                        byte2=asc(substr($0,2,1));
                        byte3=0;
                }

                if (length($0)>=3){
                        byte1=asc(substr($0,1,1));
                        byte2=asc(substr($0,2,1));
                        byte3=asc(substr($0,3,1));
                }

                base1=base64_rshift(byte1,2);
                base2=base64_lshift(base64_and(byte1,3),4)+base64_rshift(base64_and(byte2,240),4);
                base3=base64_lshift(base64_and(byte2,15),2)+base64_rshift(base64_and(byte3,192),6);
                base4=base64_and(byte3,63);
printf "byte1=%i byte2=%i byte3=%i\n", byte1, byte2, byte3;
printf "base1=%i base2=%i base3=%i base4=%i\n", base1, base2, base3, base4;
                if (length($0)==1){
                        result=result substr(BASE64,base1+1,1);
                        result=result substr(BASE64,base2+1,1);
                        result=result "==";
                        $0="";
                }

                if (length($0)==2){
                        result=result substr(BASE64,base1+1,1);
                        result=result substr(BASE64,base2+1,1);
                        result=result substr(BASE64,base3+1,1);
                        result=result "=";
                        $0="";
                }

                if (length($0)>=3){
                        result=result substr(BASE64,base1+1,1);
                        result=result substr(BASE64,base2+1,1);
                        result=result substr(BASE64,base3+1,1);
                        result=result substr(BASE64,base4+1,1);
                        $0=substr($0,4);
                }
printf "Result=%s\n", result;
        }

        printf "%s",result;
}
'
}
base64encode

Mas quando há caracteres NULL na entrada, o awk irá separar a entrada em diferentes registros e fazer a saída do script incorretamente.

Por exemplo:

root@unknown:/tmp/test# echo -e "Hello 
[root@hp8 ~]# echo -e "Hello 
#!/bin/sh
base64encode()
{
/usr/bin/awk -- '
function asc(char,l_found)
{
        l_found=0;
        for (i=0;i<=255;i++){
        if (sprintf("%c",i)==char) l_found=i;
        }
        return l_found;
}

function base64_and(var,x,l_res,l_i)
{
        l_res=0;
        for (l_i=0;l_i<8;l_i++){
                if (var%2==1 && x%2==1) l_res=l_res/2+128;
                else l_res/=2;
                       var=int(var/2);
                x=int(x/2);
        }
        return l_res;
}

function base64_lshift(var,x)
{
        while(x>0){
        var*=2;
        x--;
        }
        return var;
}

function base64_rshift(var,x)
{
        while(x>0){
        var=int(var/2);
        x--;
        }
        return var;
}

BEGIN{
BASE64="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
result="";
}

{
        while (length($0)>0){
printf "Source: %s Length: %i\n",$0,length($0);
                if (length($0)==1){
                        byte1=asc(substr($0,1,1));
                        byte2=0;
                        byte3=0;
                }

                if (length($0)==2){
                        byte1=asc(substr($0,1,1));
                        byte2=asc(substr($0,2,1));
                        byte3=0;
                }

                if (length($0)>=3){
                        byte1=asc(substr($0,1,1));
                        byte2=asc(substr($0,2,1));
                        byte3=asc(substr($0,3,1));
                }

                base1=base64_rshift(byte1,2);
                base2=base64_lshift(base64_and(byte1,3),4)+base64_rshift(base64_and(byte2,240),4);
                base3=base64_lshift(base64_and(byte2,15),2)+base64_rshift(base64_and(byte3,192),6);
                base4=base64_and(byte3,63);
printf "byte1=%i byte2=%i byte3=%i\n", byte1, byte2, byte3;
printf "base1=%i base2=%i base3=%i base4=%i\n", base1, base2, base3, base4;
                if (length($0)==1){
                        result=result substr(BASE64,base1+1,1);
                        result=result substr(BASE64,base2+1,1);
                        result=result "==";
                        $0="";
                }

                if (length($0)==2){
                        result=result substr(BASE64,base1+1,1);
                        result=result substr(BASE64,base2+1,1);
                        result=result substr(BASE64,base3+1,1);
                        result=result "=";
                        $0="";
                }

                if (length($0)>=3){
                        result=result substr(BASE64,base1+1,1);
                        result=result substr(BASE64,base2+1,1);
                        result=result substr(BASE64,base3+1,1);
                        result=result substr(BASE64,base4+1,1);
                        $0=substr($0,4);
                }
printf "Result=%s\n", result;
        }

        printf "%s",result;
}
'
}
base64encode
World\!"|base64 SGVsbG8gACBXb3JsZFwhCg== [root@hp8 ~]#
World!"|./base64encode.sh Source: Hello Length: 6 byte1=72 byte2=101 byte3=108 base1=18 base2=6 base3=21 base4=44 Result=SGVs Source: lo Length: 3 byte1=108 byte2=111 byte3=32 base1=27 base2=6 base3=60 base4=32 Result=SGVsbG8g SGVsbG8gSource: World! Length: 7 byte1=32 byte2=87 byte3=111 base1=8 base2=5 base3=29 base4=47 Result=SGVsbG8gIFdv Source: rld! Length: 4 byte1=114 byte2=108 byte3=100 base1=28 base2=38 base3=49 base4=36 Result=SGVsbG8gIFdvcmxk Source: ! Length: 1 byte1=33 byte2=0 byte3=0 base1=8 base2=16 base3=0 base4=0 Result=SGVsbG8gIFdvcmxkIQ== SGVsbG8gIFdvcmxkIQ==root@unknown:/tmp/test#

Enquanto no Linux, podemos dizer que a saída não estava correta porque a entrada acima foi dividida em dois registros e o caractere NULL entre eles não é processado.

root@unknown:/tmp/test# echo -e "Hello 
[root@hp8 ~]# echo -e "Hello %pre% World\!"|base64
SGVsbG8gACBXb3JsZFwhCg==
[root@hp8 ~]#
World!"|./base64encode.sh Source: Hello Length: 6 byte1=72 byte2=101 byte3=108 base1=18 base2=6 base3=21 base4=44 Result=SGVs Source: lo Length: 3 byte1=108 byte2=111 byte3=32 base1=27 base2=6 base3=60 base4=32 Result=SGVsbG8g SGVsbG8gSource: World! Length: 7 byte1=32 byte2=87 byte3=111 base1=8 base2=5 base3=29 base4=47 Result=SGVsbG8gIFdv Source: rld! Length: 4 byte1=114 byte2=108 byte3=100 base1=28 base2=38 base3=49 base4=36 Result=SGVsbG8gIFdvcmxk Source: ! Length: 1 byte1=33 byte2=0 byte3=0 base1=8 base2=16 base3=0 base4=0 Result=SGVsbG8gIFdvcmxkIQ== SGVsbG8gIFdvcmxkIQ==root@unknown:/tmp/test#

Alguém pode me dizer como eu posso fazer o awk no meu Busybox tratar toda a entrada com caractere NULL entre um único registro?

    
por Marugao Bozu 26.12.2013 / 20:07

2 respostas

1

Se a sua instalação do BusyBox tiver o utilitário uuencode , esqueça tudo isso e use uuencode -m .

base64encode () {
  uuencode -m ignored | tail -n +2
}

Se você realmente precisa usar o awk, acho que não dá para lidar com bytes nulos. Uma solução possível é primeiro converter os bytes nulos em outra coisa, por exemplo, com aplicativos criteriosos de tr e sed . tr suporta bytes nulos como deveria, e sed não pode manipulá-los diretamente, mas os repassa. Enquanto você está nisso, traduza newlines também, senão acho que você não será capaz de dizer se o arquivo de entrada terminou em uma nova linha ou não.

sed -e 's/[a-z]/q&/g' | tr '
base64encode () {
  uuencode -m ignored | tail -n +2
}
\n' zn | awk …

Na entrada para o script awk:

  • não há bytes nulos ou novas linhas;
  • todas as letras minúsculas correspondentes a si mesmas têm um q antes delas;
  • z representa um byte nulo e n representa uma nova linha.
por 27.12.2013 / 03:34
0

Eu não testei isso exaustivamente, mas acredito que você pode definir a variável ORS to awk , o que deve fazer com que o $1 do Busybox pare de dividir em NULL.

Exemplo

sem

$ echo -e "Hello 
$ echo -e "Hello 
   ORS         The output record separator, by default a newline.
   ...
   print       Print the current record.  The output record is terminated 
               with the value of the  ORS variable.
World\!" | busybox awk -vORS=$'
$ echo -e "Hello 
$ echo -e "Hello 
   ORS         The output record separator, by default a newline.
   ...
   print       Print the current record.  The output record is terminated 
               with the value of the  ORS variable.
World\!" | busybox awk -vORS=$'%pre%' '{print $1}' HelloWorld\!
World\!" | busybox awk '{print $1}' Hello World\!
' '{print $1}' HelloWorld\!
World\!" | busybox awk '{print $1}' Hello World\!

com

%pre%

Observe que ele não foi dividido em nada, portanto, a string inteira está contida na variável awk em ORS .

Detalhes

A variável awk em %code% é o separador de registro de saída.

trecho da página de manual do awk

%pre%     
por 27.12.2013 / 00:54