AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • Início
  • system&network
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • Início
  • system&network
    • Recentes
    • Highest score
    • tags
  • Ubuntu
    • Recentes
    • Highest score
    • tags
  • Unix
    • Recentes
    • tags
  • DBA
    • Recentes
    • tags
  • Computer
    • Recentes
    • tags
  • Coding
    • Recentes
    • tags
Início / unix / Perguntas / 762948
Accepted
Felipe Evaristo
Felipe Evaristo
Asked: 2023-12-03 08:27:50 +0800 CST2023-12-03 08:27:50 +0800 CST 2023-12-03 08:27:50 +0800 CST

Como posso reformatar blocos de dados até chegar ao final do arquivo?

  • 772

Eu tenho um arquivo parecido com este:

# Time-averaged data for fix avetimeall
# TimeStep Number-of-rows
# Row c_gyrationchunkall
1000 3
1 2.09024e-14
2 4.88628
3 5.69321
2000 3
1 2.10518e-14
2 8.33702
3 8.83162
3000 3
1 1.96656e-14
2 12.1396
3 11.5835
...

No meu arquivo, as três primeiras linhas são sempre cabeçalhos. Após os cabeçalhos, meu arquivo lista blocos de dados do mesmo tamanho, cada um começando com um subcabeçalho rotulado. Quero reorganizar os dados em meu arquivo de modo que os dados em cada bloco sejam enviados em uma linha começando com a parte relevante do rótulo desse bloco e listando posteriormente os valores de dados relevantes desse bloco, todos separados uns dos outros por espaços . Por exemplo, quero converter a amostra acima em:

# Time-averaged data for fix avetimeall
# TimeStep c_gyrationchunkall
1000 2.09024e-14 4.88628 5.69321
2000 2.10518e-14 8.33702 8.83162
3000 1.96656e-14 12.1396 11.5835
...

Como faço isso no Bash? Tenho alguma experiência em Bash, mas infelizmente não o suficiente para lidar com esse problema rapidamente...

bash
  • 5 5 respostas
  • 735 Views

5 respostas

  • Voted
  1. Best Answer
    Ed Morton
    2023-12-03T19:06:19+08:002023-12-03T19:06:19+08:00

    Usando qualquer awk, independentemente de o 3número de linhas em um bloco poder variar ou não:

    $ awk '
        NR == 2 { $3=""; saved=$0; next }
        NR == 3 { $0=saved $3 }
        NR  < 4 { print; next }
        !numLines {
            numLines = $2
            printf "%s%s", $1, OFS
            next
        }
        { printf "%s%s", $2, (--numLines ? OFS : ORS) }
    ' file
    # Time-averaged data for fix avetimeall
    # TimeStep c_gyrationchunkall
    1000 2.09024e-14 4.88628 5.69321
    2000 2.10518e-14 8.33702 8.83162
    3000 1.96656e-14 12.1396 11.5835
    

    Seguindo uma discussão sob a resposta de Xavier G sobre uma preferência de estilo para legibilidade, aqui está um script awk escrito no mesmo estilo daquele script de shell (e contido em um script de shell para que se comporte da mesma maneira externamente), mas será executado ordens de magnitude mais rápidas* e mais robustas e portáveis ​​que o shell script:

    $ cat ./script_filename
    #!/usr/bin/env bash
    
    awk '
        BEGIN {
            # Reformat comments:
            getline first_line
            print first_line
            getline; split($0,line2)
            getline; split($0,line3)
            printf "# %s %s\n", line2[2], line3[3]
    
            # Reformat data:
            while ( getline > 0 ) {
                timestep=$1; number_of_rows=$2
                printf "%s", timestep
                for ( i=1; i<=number_of_rows; i++ ) {
                    getline; row_value=$NF
                    printf " %s", row_value
                }
                print ""
            }
        }
    '
    

    $ ./script_filename < input
    # Time-averaged data for fix avetimeall
    # TimeStep c_gyrationchunkall
    1000 2.09024e-14 4.88628 5.69321
    2000 2.10518e-14 8.33702 8.83162
    3000 1.96656e-14 12.1396 11.5835
    

    * Aqui estão os resultados do tempo da terceira execução da execução do script bash versus o script awk acima em um arquivo contendo 90.000 registros de OPs:

    $ time ./script_bash < file > /dev/null
    
    real    0m9.425s
    user    0m5.062s
    sys     0m4.139s
    

    $ time ./script_awk < file > /dev/null
    
    real    0m0.265s
    user    0m0.171s
    sys     0m0.000s
    
    • 6
  2. jubilatious1
    2023-12-03T13:49:10+08:002023-12-03T13:49:10+08:00

    Usando Raku (anteriormente conhecido como Perl_6)

    Use skippara esquecer as linhas de cabeçalho por enquanto:

    ~$ raku -e 'my @a = lines.skip(3).rotor(4, partial => True).map: *.words; .[0,3,5,7].put for @a;'  file
    
    #OR
    
    ~$ raku -e 'my @a = lines.skip(3).batch(4).map: *.words; .[0,3,5,7].put for @a;'  file
    

    Acima está uma resposta codificada em Raku, um membro da família Perl de linguagens de programação. Resumidamente, linessão lidos e skipexecutam ping nas três primeiras linhas do cabeçalho. Cada 4 linhas são rotoreditadas/ batcheditadas juntas, incluindo partial"rotorings" finais no final do arquivo. Enquanto estamos nisso, vamos dividir cada rotor/ batchem espaços em branco separados words.

    Esses rotores/lotes de 4 linhas, cada um quebrado no espaço em branco, são salvos em uma @matriz -sigilada chamada @a. Finalmente (na segunda instrução), o uso de forcada @aposição é iterado through e out put, tomando cuidado para que elementos indesejados sejam descartados (por meio de colchetes de indexação [0,3,5,7]).

    Entrada de amostra:

    # Time-averaged data for fix avetimeall
    # TimeStep Number-of-rows
    # Row c_gyrationchunkall
    1000 3
    1 2.09024e-14
    2 4.88628
    3 5.69321
    2000 3
    1 2.10518e-14
    2 8.33702
    3 8.83162
    3000 3
    1 1.96656e-14
    2 12.1396
    3 11.5835
    

    Saída de amostra:

    1000 2.09024e-14 4.88628 5.69321
    2000 2.10518e-14 8.33702 8.83162
    3000 1.96656e-14 12.1396 11.5835
    

    Em relação às linhas de cabeçalho, poderia ser igualmente fácil iniciar o código Raku com duas putinstruções, por exemplo put "Time-averaged data...";, etc. Mas, de fato, o seguinte funciona para fornecer a saída desejada pelo OP:

    ~$ raku -e 'lines[0].put; .words[0..1, *-1].put for lines[0..1].rotor(2);  \
                my @a = lines.rotor(4, partial => True).map: *.words;          \
                .[0,3,5,7].put for @a;'  file
    ## Time-averaged data for fix avetimeall
    # TimeStep c_gyrationchunkall
    1000 2.09024e-14 4.88628 5.69321
    2000 2.10518e-14 8.33702 8.83162
    3000 1.96656e-14 12.1396 11.5835
    

    https://raku.org

    • 3
  3. Prabhjot Singh
    2023-12-03T19:31:31+08:002023-12-03T19:31:31+08:00

    Usando AWK :

    $ awk '
        NR==2{sub(/[[:space:]]+[^[:space:]]+$/,"");rec = $0; next}
        NR==3{$0 = rec OFS $NF};
        NR<4;                                
        NR>3{printf "%s", (NR%4==0) ? ((NR==4) ? "" : ORS) $1 : ($1="")$0 }
       END{if (NR)print ""}' 
    
    $ awk '
       NR==2{sub(/[[:space:]]+[^[:space:]]+$/,"");rec = $0; next}
       NR==3{$0 = rec OFS $NF};
       NR<4;
       $NF ~ /^[0-9]+$/{a=$NF;n=NR+a; sub(/[[:space:]]+[^[:space:]]+$/,""); printf "%s", $0; next}                    
       NR<=n{$1 =""; printf "%s", $0((NR==n) ? ORS : "") }'
    
    • 3
  4. Xavier G.
    2023-12-03T12:22:38+08:002023-12-03T12:22:38+08:00

    Resposta rápida e suja - sinta-se à vontade para executar shellcheckisso:

    #!/usr/bin/env bash
    
    # Reformat comments:
    read -r first_line
    echo "${first_line}"
    read -r sharp line2_word1 line2_word2
    read -r sharp line3_word1 line3_word2
    echo "# ${line2_word1} ${line3_word2}"
    
    # Reformat data:
    while read -r timestep number_of_rows; do
        echo -n "${timestep}"
        for (( i=1; i<=number_of_rows; i++ )); do
            read -r row value
            echo -n " ${value}"
        done
        echo
    done
    

    Uso:./script_filename < input

    Limitações:

    • este script assume que as linhas de dados estão ordenadas (ou seja, 1, 2, 3, conforme mostrado no exemplo)
    • este script não lida com dados interrompidos (por exemplo, anunciando 3 linhas de dados, mas fornecendo apenas 1)
    • 2
  5. elmo
    2023-12-04T05:53:53+08:002023-12-04T05:53:53+08:00

    Com as advertências mencionadas na sua pergunta e usando sua entrada de amostra como arquivo q762948, você pode fazer isso com um simples comando awk:

    $ head -2 q762948 >result.txt
    # dump the comments as required
    $ tail +4 q762948 | awk '{c=(NR-1)%4} c==0{p=$1;print ""} c>0{p=$2}{printf p"  "}'>>result.txt    
    $ cat result.txt
    
    # Time-averaged data for fix avetimeall
    # TimeStep Number-of-rows
    
    1000  2.09024e-14  4.88628  5.69321  
    2000  2.10518e-14  8.33702  8.83162  
    3000  1.96656e-14  12.1396  11.5835
    
    • 2

relate perguntas

  • exportar variáveis ​​​​env programaticamente, via stdout do comando [duplicado]

  • Problema estranho ao passar variáveis ​​do arquivo de texto

  • Enquanto a linha lê mantendo os espaços de escape?

  • ordem de substituição de processos `te` e `bash`

  • Execute um script muito lento até que seja bem-sucedido

Sidebar

Stats

  • Perguntas 205573
  • respostas 270741
  • best respostas 135370
  • utilizador 68524
  • Highest score
  • respostas
  • Marko Smith

    Possível firmware ausente /lib/firmware/i915/* para o módulo i915

    • 3 respostas
  • Marko Smith

    Falha ao buscar o repositório de backports jessie

    • 4 respostas
  • Marko Smith

    Como exportar uma chave privada GPG e uma chave pública para um arquivo

    • 4 respostas
  • Marko Smith

    Como podemos executar um comando armazenado em uma variável?

    • 5 respostas
  • Marko Smith

    Como configurar o systemd-resolved e o systemd-networkd para usar o servidor DNS local para resolver domínios locais e o servidor DNS remoto para domínios remotos?

    • 3 respostas
  • Marko Smith

    apt-get update error no Kali Linux após a atualização do dist [duplicado]

    • 2 respostas
  • Marko Smith

    Como ver as últimas linhas x do log de serviço systemctl

    • 5 respostas
  • Marko Smith

    Nano - pule para o final do arquivo

    • 8 respostas
  • Marko Smith

    erro grub: você precisa carregar o kernel primeiro

    • 4 respostas
  • Marko Smith

    Como baixar o pacote não instalá-lo com o comando apt-get?

    • 7 respostas
  • Martin Hope
    user12345 Falha ao buscar o repositório de backports jessie 2019-03-27 04:39:28 +0800 CST
  • Martin Hope
    Carl Por que a maioria dos exemplos do systemd contém WantedBy=multi-user.target? 2019-03-15 11:49:25 +0800 CST
  • Martin Hope
    rocky Como exportar uma chave privada GPG e uma chave pública para um arquivo 2018-11-16 05:36:15 +0800 CST
  • Martin Hope
    Evan Carroll status systemctl mostra: "Estado: degradado" 2018-06-03 18:48:17 +0800 CST
  • Martin Hope
    Tim Como podemos executar um comando armazenado em uma variável? 2018-05-21 04:46:29 +0800 CST
  • Martin Hope
    Ankur S Por que /dev/null é um arquivo? Por que sua função não é implementada como um programa simples? 2018-04-17 07:28:04 +0800 CST
  • Martin Hope
    user3191334 Como ver as últimas linhas x do log de serviço systemctl 2018-02-07 00:14:16 +0800 CST
  • Martin Hope
    Marko Pacak Nano - pule para o final do arquivo 2018-02-01 01:53:03 +0800 CST
  • Martin Hope
    Kidburla Por que verdadeiro e falso são tão grandes? 2018-01-26 12:14:47 +0800 CST
  • Martin Hope
    Christos Baziotis Substitua a string em um arquivo de texto enorme (70 GB), uma linha 2017-12-30 06:58:33 +0800 CST

Hot tag

linux bash debian shell-script text-processing ubuntu centos shell awk ssh

Explore

  • Início
  • Perguntas
    • Recentes
    • Highest score
  • tag
  • help

Footer

AskOverflow.Dev

About Us

  • About Us
  • Contact Us

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve