공백으로 구분된 단어 목록을 터미널 너비에 맞는 테이블 열로 축소하는 방법

공백으로 구분된 단어 목록을 터미널 너비에 맞는 테이블 열로 축소하는 방법

다음과 같이 공백으로 구분된 일련의 단어를 테이블 형식으로 출력하고, 한 줄씩 채워서 터미널 너비를 초과하지 않고 사용 가능한 공간을 최적으로 활용하고 싶습니다.

+-----------------------------------------------+
|polite      babies      embarrass   rightful   | 
|aspiring    scandalous  mut         disgusted  |
|bell        deeply      writer      jumbled    |
|respired    craggy                             |

(상자는 터미널의 너비를 설명하며 출력의 일부가 아닙니다)

fold생각나는 명령은 column이렇습니다.

$ fold words -s -w $COLUMNS | column -t

$COLUMNS이것은 거의 작동하지만 출력은 먼저 해당 너비 내에서 축소된 다음 공백을 늘려 정렬하기 때문에 (터미널 너비)보다 넓어집니다 .

나에게 필요한 것은 이 둘이 하나로 결합된 효과이다. 이를 수행할 수 있는 명령줄 도구(또는 내장 쉘)가 있습니까?

답변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( bsdmainutilsDebian의 패키지):

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개의 공백이 있습니다. 를 사용하여 1로 변경할 수 있습니다 -g 1.

관련 정보