Awk pode ler novas linhas com escape? Ou seja leia as novas linhas do passado

2

Eu tenho comentários assim:

entry1line1
entry2line1\
entry2line2\
entry2line3
entry3line1

Eu gostaria de ler essa entrada em um array no AWK, para então processá-la junto com as novas linhas incorporadas. Isso é possível? Seria melhor não usar os recursos do GNU.

    
por Will Davies 26.05.2016 / 09:51

4 respostas

2

Com posix awk você pode usar o getline

awk '{while(/\$/){getline tmp;$0=$0"\n"tmp}print "<LINE>"$0"<LINE>"}' file

Continua adicionando a próxima linha, contanto que a última linha termine em \ .

<LINE>entry1line1<LINE>
<LINE>entry2line1\
entry2line2\
entry2line3<LINE>
<LINE>entry3line1<LINE>

Same in perl

perl -ne '$_.=<> while /\$/;chomp;print "<LINE>$_<LINE>\n"' file
    
por 26.05.2016 / 10:37
1

Usando o GNU awk:

$ awk '{printf "%s%s%s","line=",$0,RT}' RS='[^\\]\n' text
line=entry1line1
line=entry2line1\
entry2line2\
entry2line3
line=entry3line1

Como você pode ver, as linhas que terminam com \ são unidas à próxima linha. Isso ocorre porque o separador de registro RS foi redefinido como qualquer barra invertida seguida por uma nova linha. Em outras palavras, a barra invertida-nova linha não é um separador de registro.

Um pequeno truque aqui é que o separador de registro engole o último caractere do registro. Esse caractere, no entanto, é salvo para nós na variável interna RT . Uma pequena alteração no programa corrige o valor de $0 no início do código para que esse problema desapareça:

$ awk '{$0=$0 substr(RT,1,1)} {print "line=",$0}' RS='[^\\]\n' text
line= entry1line1
line= entry2line1\
entry2line2\
entry2line3
line= entry3line1

RT contém todo o separador de registros observado real. No nosso caso, isso significa que ele tem o último caractere do registro e o caractere de nova linha que se segue. Conseqüentemente, no código acima, substr é usado para adicionar o primeiro caractere de RT ao final de $0 .

    
por 26.05.2016 / 10:00
0

Você pode alterar o separador de registros em POSIX awk alterando RS . POSIX não especifica se isso pode ser uma expressão regular, dizendo apenas

The unspecified behavior from using multi-character RS values is to allow possible future extensions based on extended regular expressions used for record separators. Historical implementations take the first character of the string and ignore the others.

No entanto, você pode ler o arquivo inteiro como uma string (escolhendo% RS ), ou usando getline , olhar para as extremidades das linhas e juntar o resultado conforme necessário.

    
por 26.05.2016 / 09:57
0

O livro de receitas do perl tem um exemplo de como fazer isso usando o perl.

Eu adaptei esse exemplo para trabalhar com <> (stdin e / ou qualquer nome de arquivo é dado como args na linha de comando) ao invés de um identificador de arquivo nomeado, e também para manter a nova linha após o \ continuation (que é um pouco incomum - é muito mais comum querer que uma linha contínua seja tratada como uma linha longa, com continuações unidas a nada ou talvez a um caractere de espaço).

perl -e '
$count=1;
while (defined($line = <>) ) {
    chomp($line);
    if ($line =~ s/\$//) {
        $line .= "\n" . <>;
        redo unless eof();
    }
    # process full record in $line here
    printf "%04i:\"%s\"\n\n", $count++,$line;
}' willdavies.txt 

Você pode fazer o que quiser com $line após o comentário que diz # process full record... . Eu escolhi apenas imprimir cada linha como um parágrafo separado com um contador de linha com preenchimento zero. Eu também adicionei aspas em torno de $line para que você possa ver exatamente o que está em $line (e o que não é).

Saída:

0001:"entry1line1"

0002:"entry2line1
entry2line2
entry2line3"

0003:"entry3line1"
    
por 26.05.2016 / 11:00