Use o awk interativamente através de um tubo

5

Analisando esta questão , notei que awk não consegue ler o usuário entrada se o arquivo está sendo canalizado para entrada padrão, mas não comportar-se como esperado se ler entrada de um arquivo fornecido como um comando parâmetro de linha.

Por exemplo, se você tiver o seguinte bloco BEGIN no seu script awk :

BEGIN {
    printf "Enter input: "
    getline var < "-"
}

Se você executar como awk -f ./script.awk file.txt , ele solicitará prompt para entrada do usuário e, em seguida, continuará processando file.txt . Contudo, se você correr como cat file.txt | awk -f ./script.awk , suponho awk vai interpretar o que está recebendo do tubo como entrada do usuário (então getline preencherá var com a primeira linha de file.txt ).

Existe uma maneira de fazer o awk se comportar como se estivesse lendo de um arquivo, mas sendo usado em um pipe?

Eu posso usar um arquivo temporário, claro, mas isso está longe de ser elegante.

    
por Kira 14.12.2015 / 21:44

4 respostas

3

Em vez de um arquivo temporário, você pode usar o suporte do seu shell para substituição de processo (isso assume bash , zsh ou algumas implementações de ksh (o recurso foi introduzido por ksh88)):

awk -f ./script.awk <(cat file.txt)

Isso fornecerá awk um nome de arquivo no lugar da construção <(...) que, quando lida, conterá a saída do comando incluído.

    
por 14.12.2015 / 21:57
5

A substituição de processos funcionaria em casos simples, mas aqui é uma maneira genérica que permite dialogar com o usuário do console enquanto processa os dados enviados:

BEGIN {
    printf "Enter input: " > "/dev/tty"
    getline var < "/dev/tty"
    print var
}
    
por 14.12.2015 / 22:11
2

Se isso se adequar ao seu fluxo de trabalho, você pode fazer o próprio awk abrir o pipe. Você não pode fazer isso por um elemento ARGV , então você não terá a iteração automática do awk nas linhas lidas do pipe. Em vez disso, o awk lerá os arquivos passados como argumentos da linha de comando ou a partir da entrada padrão, se não houver argumentos de arquivo.

{
    printf "Enter input: "
    getline var
    while (("cat file.txt" | getline) > 0) { … }
}

Essa estrutura não se encaixa bem no seu exemplo de brinquedo, mas estou mencionando isso porque ela pode se encaixar no seu verdadeiro problema.

    
por 15.12.2015 / 02:03
1

se o seu sistema suportar os links /dev/fd/[num] ou o seu awk for GNU awk , isso provavelmente funcionará onde awk -f ./script.awk file.txt :

{ some_cmd | 3<&0 <&4 4<&- awk -f ./script.awk /dev/fd/3; } 4<&0
    
por 15.12.2015 / 03:53

Tags