Print a file in multiple columns based on delimiter

前端 未结 4 822
广开言路
广开言路 2021-01-23 08:37

This seems like a simple task, but using duckduckgo I wasn\'t able to find a way to properly do what I\'m trying to.

The main question is: How do I split the output of a

相关标签:
4条回答
  • 2021-01-23 09:18

    The question is tagged as Perl so here is a possible Perl answer:

    #!/usr/bin/env perl
    use strict;
    use warnings;
    
    my $is_col1 = 1;
    my $in_block = 0;
    my @col1;
    
    while (<DATA>) {
        chomp;
        if (/^\s*-+\s*$/ ... /^\s*-+\s*$/) {
            $in_block = 1;
            if ($is_col1) {
                push @col1, $_;
            }
            else {
                printf "%-40s%-40s\n", shift @col1 // '', $_;
            }
    
        }
        else {
            if ($in_block) {
                $in_block = ! $in_block;
                $is_col1 = ! $is_col1;
                print "\n" if $is_col1; # line separating blocks
            }
        }
    }
    
    print join("\n", @col1), "\n\n" if @col1;
    
    __DATA__
    -----------------------------------
    Some data
    that varies in line length
    -----------------------------------
    
    -----------------------------------
    More data that is seperated
    by a new line and dashes
    with a longer column2
    -----------------------------------
    
    
    -----------------------------------
    The odd last column
    -----------------------------------
    

    Output:

    -----------------------------------     -----------------------------------
    Some data                               More data that is seperated
    that varies in line length              by a new line and dashes
    -----------------------------------     with a longer column2
                                            -----------------------------------
    
    -----------------------------------
    The odd last column
    -----------------------------------
    
    0 讨论(0)
  • 2021-01-23 09:18

    Alright, since apprently there is no clean way to do this I came up with my own solution. It's a bit messy and requires GNU screen to be installed, but it works. Any amount of lines within or around the blocks, 50% of the screen automatically resizing and each column prints independantly from each other with a fixed amount of newlines between them. Also automatic updates every x seconds. (120 in my example)

    #!/bin/bash
    
    screen -S testscr -X layout save default
    screen -S testscr -X split -v
    screen -S testscr -X screen tail -f /tmp/testscr1.txt
    screen -S testscr -X focus
    screen -S testscr -X screen tail -f /tmp/testscr2.txt
    
    while : ; do
        echo "" > /tmp/testscr1.txt
        echo "" > /tmp/testscr2.txt
        cfile=1 # current column
        ctype=0 # start or end of block
    
        while read; do
            if [[ $REPLY == "------------------------------------------------------------" ]]; then
                if [[ $ctype -eq 0 ]]; then
                    ctype=1
                else
                    if [[ $cfile -eq 1 ]]; then
                        echo "${REPLY}" >> /tmp/testscr1.txt
                        echo "" >> /tmp/testscr1.txt
                        echo "" >> /tmp/testscr1.txt
                        cfile=2
                    else
                        echo "${REPLY}" >> /tmp/testscr2.txt
                        echo "" >> /tmp/testscr2.txt
                        echo "" >> /tmp/testscr2.txt
                        cfile=1
                    fi
                    ctype=0
                fi
            fi
            if [[ $ctype -eq 1 ]]; then
                if [[ $cfile -eq 1 ]]; then
                    echo "${REPLY}" >> /tmp/testscr1.txt
                else
                    echo "${REPLY}" >> /tmp/testscr2.txt
                fi
            fi
        done < "$1"
        sleep 120
    done
    

    First, start a screen session with screen -S testscr then, either within or outside the session, execute the script above. This will split the screen vertically using 50% per column and execute tail -f on both columns, afterwards it will go through the input file and write block by block to each tmp. file in the desired way. Since it's in an infinite while loop it's essentially automatically updating the shown output every x seconds (here 120).

    0 讨论(0)
  • 2021-01-23 09:27

    Assuming file contains uniform blocks of five lines each, using paste, sed, and printf:

    c=$((COLUMNS/2)) 
    paste -d'#' <(sed -n 'p;n;p;n;p;n;p;n;p;n;n;n;n;n' file) \
                <(sed -n 'n;n;n;n;n;p;n;p;n;p;n;p;n;p' file) | 
    sed 's/.*/"&"/;s/#/" "/' | 
    xargs -L 1 printf "%-${c}s %-${c}s\n"
    

    Problem with OP spec

    The OP reports that the block lengths may vary, and should be separated by a fixed number of lines. Even numbered blocks go in Column A, odd numbered blocks in Column B.

    That creates a tail -f problem then. Suppose the block lengths of the source input begin with 1000 lines, then one line, 1000, 1, 1000, 1, etc. So Column A gets all the 1000 line blocks, and Column B gets all the one line blocks. Let's say the blocks in the output are separated by 1 line each. So one block in Column A lines up with 500 blocks in Column B. So for a terminal with scrolling output, that means before we can output the first block in Column A, we have to wait for 1000 blocks of input. To output the third block in Column A, (just below the first block), we have to wait for 2000 blocks of input.

    If the blocks are added to the input file relatively slowly, with a one second delay between blocks, then it will take three seconds for the block 3 to appear in the input file, but it will take 33 minutes for block 3 to be displayed in the output file.

    0 讨论(0)
  • 2021-01-23 09:39

    This script is getting max width of current terminal and splitting it in 2, then printing records split by RS="\n\n" separator, print the first found and placing the cursor at the first line/last column of it to write the next record.

    #!/bin/bash
    
    tput clear
    # get half current terminal width
    twidth=$(($(tput cols)/2))
    
    tail -n 100 -f test.txt | stdbuf -i0 -o0 gawk -v twidth=$twidth 'BEGIN{ RS="\n\n"; FS=OFS="\n"; oldNF=0 } {
        sep="-----------------------------------"
        pad="                    "
        printf "%-" twidth "s", $0
    
        getline
    
        for(i = 1; i <= NF; i++){
        # move cursor to first line, last column of previous record
        print "\033[" oldNF ";" twidth "f" $i
        oldNF+=1
        }
    }'
    

    Here's a simpler version

    gawk 'BEGIN{ RS="[-]+\n\n"; FS="\n" } {
        sep="-----------------------------------"
        le=$2
        lo=$3
        getline
    
        printf "%-40s %-40s\n", sep,sep
        printf "%-40s %-40s\n", le,$2
        printf "%-40s %-40s\n", lo,$3
        printf "%-40s %-40s\n\n", sep,sep
    }' test.txt
    

    Output

    -----------------------------------      -----------------------------------     
    Some data                                More data that is seperated             
    that varies in line length               by a new line and dashes                
    -----------------------------------      -----------------------------------     
    
    -----------------------------------      -----------------------------------     
    Some data                                More data that is seperated             
    that varies in line length               by a new line and dashes                
    -----------------------------------      ----------------------------------- 
    
    0 讨论(0)
提交回复
热议问题