Как обернуть строки в столбцах в Linux - PullRequest
2 голосов
/ 26 июня 2019

У меня есть файл с разделителями-запятыми, который я форматирую, чтобы создать 2 столбца с помощью printf. Я использую awk, чтобы сгруппировать содержимое в похожие группы, чтобы я мог распечатать их в красиво отформатированных столбцах.

Форматирование работает, но содержимое массива переносится на новые строки, а не внутри самого столбца.

Пример входного файла:

1,test,test1,test1
2,test,test1,test2
2,test,test1,test2
2,test,test1,test2
2,test,test1,test2
2,test,test1,test2
2,test,test1,test2
2,test,test1,test2
2,test,test1,test2
2,test,test1,test2
2,test,test1,test2
2,test,test1,test2
2,test,test1,test2`

Используемая команда:

awk -F"," 'NR>1 {a[$3]=a[$3] ? a[$3]", "$4" ("$2")" : $4" ("$2")"}
  END {for (i in a) {print i":"a[i]}}' test.dat |
sort |
awk -F":" 'BEGIN { printf "%-15s %-10s\n", "COLUMN1","COLUMN2"; printf "%-15s %-10s\n", "-----------","----------"}
  { printf "%-15s %-10s\n", $1,$2}'

Я также знаю и пытался использовать column -t -s"," и pr

Результат похож на (имитирующий пример):

COLUMN1     COLUMN2
========     =======
1            test1
2            test2, test2, test2, test2, test2, test2,test2, test2, test2,test2, test2, test2, test2, test2

Как мне обернуть второй столбец (даже первый, если он слишком длинный), чтобы он помещался в пределах своего кадра?

COLUMN1     COLUMN2
========     =======
1            test1
2            test2, test2, test2, test2, test2, test2,test2, test2, 
             test2,test2, test2, test2, test2, test2

Ответы [ 2 ]

2 голосов
/ 26 июня 2019

Давайте представим, что это то, что делает ваш оригинальный скрипт, учитывая ваш опубликованный пример ввода и вывод, который, как вы говорите, вы получаете:

$ cat tst.awk
BEGIN { FS=","; OFS="\t" }
{ vals[$1] = ($1 in vals ? vals[$1] ", " : "") $4 }
END {
    print "column1", "column2"
    print "=======", "======="

    for (key in vals) {
        print key, vals[key]
    }
}

$ awk -f tst.awk file
column1 column2
======= =======
1       test1
2       test2, test2, test2, test2, test2, test2, test2, test2, test2, test2, test2, test2

Будет ли это хорошей отправной точкой для вашего вопроса, и теперь вы хотитезавернуть каждый столбец?Если это так, то я бы воспользовался существующим инструментом UNIX, таким как fold или fmt, чтобы сделать перенос для вас, чтобы вам не пришлось писать свой собственный код для обработки разбиения на пробелы по сравнению со средним словом и т. Д.:

$ cat tst.awk
BEGIN { FS=","; OFS="\t" }
{ vals[$1] = ($1 in vals ? vals[$1] ", " : "") $4 }
END {
    print "column1", "column2"
    print "=======", "======="

    for (key in vals) {
        numKeyLines = wrap(key,15,keyArr)
        numValLines = wrap(vals[key],50,valArr)
        numLines = (numKeyLines > numValLines ? numKeyLines : numValLines)
        for (lineNr=1; lineNr<=numLines; lineNr++) {
            print keyArr[lineNr], valArr[lineNr]
        }
    }
}

function wrap(inStr,wid,outArr,         cmd,line,numLines) {
    if ( length(inStr) > wid ) {
        cmd = "printf \047%s\n\047 \"" inStr "\" | fold -s -w " wid+0
        while ( (cmd | getline line) > 0 ) {
            outArr[++numLines] = line
        }
        close(cmd)
    }
    else {
        outArr[++numLines] = inStr
    }
    return numLines+0
}

.

$ awk -f tst.awk file
column1 column2
======= =======
1       test1
2       test2, test2, test2, test2, test2, test2, test2,
        test2, test2, test2, test2, test2

Если у вас есть много полей, которые нужно обернуть, то это не будет быстрым из-за появления подоболочки для каждого вызова fold Итак, вот версия awk, которая разбивается на пробелы, когда это возможно, проверьте ее на крайние случаи и подгоните под костюм:

$ cat tst.awk
BEGIN { FS=","; OFS="\t" }
{ vals[$1] = ($1 in vals ? vals[$1] ", " : "") $4 }
END {
    print "column1", "column2"
    print "=======", "======="

    for (key in vals) {
        numKeyLines = wrap(key,15,keyArr)
        numValLines = wrap(vals[key],50,valArr)
        numLines = (numKeyLines > numValLines ? numKeyLines : numValLines)
        for (lineNr=1; lineNr<=numLines; lineNr++) {
            print keyArr[lineNr], valArr[lineNr]
        }
    }
}

function wrap(inStr,wid,outArr,         lineEnd,numLines) {
    while ( length(inStr) > wid ) {
        lineEnd = ( match(substr(inStr,1,wid),/.*[[:space:]]/) ? RLENGTH - 1 : wid )
        outArr[++numLines] = substr(inStr,1,lineEnd)
        inStr = substr(inStr,lineEnd+1)
        sub(/^[[:space:]]+/,"",inStr)
    }
    outArr[++numLines] = inStr
    return numLines
}

$ awk -f tst.awk file
column1 column2
======= =======
1       test1
2       test2, test2, test2, test2, test2, test2, test2,
        test2, test2, test2, test2, test2
0 голосов
/ 27 июня 2019

Вот версия, в которой вместо awk используется perl:

#!/usr/bin/env perl
use warnings;
use strict;

my ($col1, $col4, @col4data);

print <<EOF;
COLUMN1     COLUMN2
=======     =======
EOF

{
  my $line = <>;
  chomp $line;
  ($col1, $col4data[0]) = (split /,/, $line)[0,3];
}

while (<>) {
  chomp;
  my ($c, $a) = (split /,/)[0,3];
  if ($c ne $col1) {
    $col4 = join ", ", @col4data;
    write;
    @col4data = ();
    $col1 = $c;
  }
  push @col4data, $a;
}

$col4 = join ", ", @col4data;
write;

format STDOUT =
@<<<<<<<    ^<<<<<<<<<<<<<<<<<<<<<<
$col1,      $col4
~~          ^<<<<<<<<<<<<<<<<<<<<<<
            $col4
.

Пример:

$ perl columns.pl input.csv
COLUMN1     COLUMN2
=======     =======
1           test1
2           test2, test2, test2,
            test2, test2, test2,
            test2, test2, test2,
            test2, test2, test2

Волшебство здесь заключается в переносе строк с использованием выходного формата режима заполнения. Отрегулируйте ширину по мере необходимости, добавив больше < к очевидным частям в описании format.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...