[英]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中有兩列布局的方式的人也獲得了一些信息。 我嘗試了column
和pr
,兩者都沒有按預期工作。 (我在評論中對此進行了詳細闡述)
編輯:要清楚,我正在尋找一個通用的方法。 瀏覽文件,在分隔符之間獲取數據,將其放到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
----------------------------------- -----------------------------------
假設文件包含每行五行的統一塊,使用paste
, sed
和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"
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.