次のようにスペースで区切られた一連の単語をテーブル形式で出力し、1行ずつ埋め、端末の幅を超えずに利用可能なスペースを最適に活用したいと思います。
+-----------------------------------------------+
|polite babies embarrass rightful |
|aspiring scandalous mut disgusted |
|bell deeply writer jumbled |
|respired craggy |
(ボックスは端末の幅を説明し、出力の一部ではありません)
fold
思い出させる命令はcolumn
こうです。
$ fold words -s -w $COLUMNS | column -t
$COLUMNS
これはほぼうまく機能しますが、出力は最初にその幅内で縮小され、次にスペースを増やして整列するため(ターミナル幅)よりも広くなります。
私にとって必要なのは、この2つが1つにまとめられた効果です。これを実行できるコマンドラインツール(または組み込みシェル)はありますか?
答え1
各列の幅と受け入れることができる列の最大数を決定するには、可能なすべての列数(2からCOLUMNS / 2まで)の合計幅を取得する必要があるようです。
そしてperl
:
#! /usr/bin/perl
use List::Util qw(sum);
$/ = undef;
@word = <> =~ /\S+/g;
$max = $ENV{COLUMNS}/2;
for ($i = 0; $i <= $#word; $i++) {
$l = length $word[$i];
for ($c = 2; $c <= $max; $c++) {
if ($l > $w[$c][$i%$c]) {
$w[$c][$i%$c] = $l
}
}
}
for ($c = $max; $c > 1; $c--) {
last if $c + sum(@{$w[$c]}) - 1 <= $ENV{COLUMNS}
}
if($c > 1) {
@w = @{$w[$c]};
for ($i = 0; $i <= $#word; $i++) {
if (($i+1)%$c && $i < $#word) {
printf "%-*s ", $w[$i%$c], $word[$i]
} else {
print "$word[$i]\n"
}
}
} else {
print "$_\n" for @word
}
例:
$ lorem -w 50 | COLUMNS=60 that-script
minima aut veritatis laudantium qui voluptatem
est nostrum quis enim placeat hic
voluptas ab ratione sit hic sit
pariatur et provident voluptas aut odio
aut vero atque voluptatem amet voluptatem
ipsum iusto omnis tenetur ratione ratione
illo ea odit excepturi quisquam aut
nobis porro incidunt corrupti maxime ad
est sunt
ASCII以外のテキストについては、以下を参照してください。文字列の表示幅を取得します。文字列の表示幅を決定します。それは次のとおりです。
#! /usr/bin/perl
use Text::CharWidth qw(mbswidth);
use List::Util qw(sum);
$/ = undef;
@word = <> =~ /\S+/g;
$max = $ENV{COLUMNS}/2;
for ($i = 0; $i <= $#word; $i++) {
$l = mbswidth $word[$i];
for ($c = 2; $c <= $max; $c++) {
if ($l > $w[$c][$i%$c]) {
$w[$c][$i%$c] = $l
}
}
}
for ($c = $max; $c > 1; $c--) {
last if $c + sum(@{$w[$c]}) - 1 <= $ENV{COLUMNS}
}
if($c > 1) {
@w = @{$w[$c]};
for ($i = 0; $i <= $#word; $i++) {
if (($i+1)%$c && $i < $#word) {
printf $word[$i] . " " x ($w[$i%$c]+1-mbswidth($word[$i]))
} else {
print "$word[$i]\n"
}
}
} else {
print "$_\n" for @word
}
答え2
同じ間隔の列を生成するには、BSDを使用できます。rs
(また、Debianおよび派生製品(少なくとも)として移植されており、パッケージとして利用可能です)またはBSD column
(bsdmainutils
Debianのパッケージ):
tr -s '[:space:]' '[ *]' | rs -w "$COLUMNS"
tr -s '[:space:]' '[\n*]' | column -xc "$COLUMNS"
はい(垂直線は60列のワイドスクリーンの端を表示するために使用され、出力の一部ではありません):
$ lorem -w 30 | tr -s '[:space:]' '[ *]' | rs -w60
earum aspernatur ipsa sed ┃
quod sit esse quisquam ┃
animi reprehenderit porro et ┃
delectus neque esse quia ┃
pariatur amet iste voluptatem ┃
provident praesentium et sint ┃
quo animi doloribus veritatis ┃
iusto alias ┃
を使用すると、列間のスペースを減らすrs
オプションを追加できますが、-z
それによって列数は最適化されません。たとえば、上記では(AND rs -zw60
)が与えられます。
earum aspernatur ipsa sed ┃
quod sit esse quisquam ┃
animi reprehenderit porro et ┃
delectus neque esse quia ┃
pariatur amet iste voluptatem ┃
provident praesentium et sint ┃
quo animi doloribus veritatis ┃
iusto alias ┃
変える:
earum aspernatur ipsa sed quod ┃
sit esse quisquam animi reprehenderit ┃
porro et delectus neque esse ┃
quia pariatur amet iste voluptatem ┃
provident praesentium et sint quo ┃
animi doloribus veritatis iusto alias ┃
また、マルチバイト文字または幅が0または2倍の文字には機能しません。
デフォルトでは、列の間には少なくとも2つのスペースがあります。を使用して1に変更できます-g 1
。