簡體   English   中英

根據分隔符在多列中打印文件

[英]Print a file in multiple columns based on delimiter

這似乎是一個簡單的任務,但使用duckduckgo我無法找到正確做我正在嘗試的方法。

主要問題是:如何使用分隔符將linux或bash中的命令輸出拆分為多個列?

我有一個看起來像這樣的文件:(這只是一個簡化的例子)

-----------------------------------
Some data
that varies in line length
-----------------------------------

-----------------------------------
More data that is seperated
by a new line and dashes
-----------------------------------

等等。 每次將數據寫入文件時,它都會包含在一行破折號中,並由最后一個塊的空行分隔。 數據的行長度各不相同。 我想要的基本上是使用bash將文件拆分成多個列的工具或方式,如下所示:

-----------------------------------        -----------------------------------
Some data                                  More data that is seperated
that varies in line length                 by a new line and dashes
-----------------------------------        -----------------------------------

每列應占據屏幕的50%,不需要居中(如對齊)。 該文件必須 按塊進行拆分。 在中間拆分文件或類似的東西是行不通的。 我基本上希望塊1轉到左列,塊2轉到右邊,3轉到左邊,4轉到右邊,依此類推。 文件不斷更新,應立即將更新寫入屏幕。 (目前我正在使用tail -f

由於這聽起來像一個相當普遍的問題,我會歡迎一般的方法,而不是只適用於我的情況的特定答案,所以來自搜索引擎尋找在bash中有兩列布局的方式的人也獲得了一些信息。 我嘗試了columnpr ,兩者都沒有按預期工作。 (我在評論中對此進行了詳細闡述)

編輯:要清楚,我正在尋找一個通用的方法。 瀏覽文件,在分隔符之間獲取數據,將其放到A列,將下一個數據放到B列,依此類推。

這個問題被標記為Perl,所以這里有一個可能的Perl答案:

#!/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
-----------------------------------

輸出:

-----------------------------------     -----------------------------------
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
-----------------------------------

此腳本獲取當前終端的最大寬度並將其拆分為2,然后打印由RS =“\\ n \\ n”分隔符拆分的記錄,打印找到的第一個並將光標放在其第一行/最后一列以寫入下一個記錄。

#!/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
    }
}'

這是一個更簡單的版本

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

產量

-----------------------------------      -----------------------------------     
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                
-----------------------------------      ----------------------------------- 

假設文件包含每行五行的統一塊,使用pastesedprintf

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"

OP規范的問題

OP報告塊長度可能會有所不同 ,並且應該用固定數量的行分隔。 偶數編號的塊位於A 列,B列編號為奇數編號的塊。

那就產生了一個tail -f問題。 假設源輸入的塊長度以1000行開始,然后是一行,1000,1,1000,1 因此, 列A獲取所有1000個行塊,而列B獲取所有一個行塊。 假設輸出中的塊每個分隔1行。 因此, A列中的一個塊與B列中的 500個塊對齊 因此對於具有滾動輸出的終端,這意味着在我們可以輸出A列中第一個塊之前,我們必須等待1000個輸入塊 要輸出A列中第三個塊(在第一個塊下面),我們必須等待2000個輸入塊

如果塊相對較慢地添加到輸入文件中,塊之間有一秒鍾的延遲,那么塊3將在輸入文件中出現需要3秒鍾,但塊3需要33分鍾才能顯示輸出文件。

好吧,既然沒有干凈的方法可以做到這一點,我提出了自己的解決方案。 它有點亂,需要安裝GNU screen ,但它的工作原理。 塊內或塊周圍的任何數量的線,50%的屏幕自動調整大小,每列獨立打印,它們之間有固定數量的換行符。 每x秒自動更新一次。 (在我的例子中為120)

#!/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

首先,使用screen -S testscr啟動一個屏幕會話,然后在會話內部或外部執行上面的腳本。 這將使用每列50%垂直分割屏幕並在兩列上執行tail -f ,然后它將通過輸入文件並逐塊寫入每個tmp。 以所需的方式提交文件。 由於它處於無限循環中,因此它基本上每x秒自動更新所顯示的輸出(此處為120 )。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM