awk - динамическое форматирование столбцов, разделенных табуляцией

Из spec :

  • Если указан операнд bs = expr и никаких преобразований кроме ] sync , noerror или notrunc запрашиваются, данные, возвращаемые из каждого входного блока, должны быть записаны как отдельный выходной блок; если read () возвращает меньше, чем полный блок, а преобразование sync не указано, результирующий выходной блок должен быть того же размера, что и входной блок.

Так что, вероятно, это и вызывает ваше замешательство. Да, поскольку dd предназначен для блокировки, по умолчанию частичные read () будут сопоставлены 1: 1 с частичным write () s, или sync d на завершающем заполнении NUL или пробелами до размера bs = , если задано conv = sync .

Это означает, что dd безопасен для копирования данных (без риска повреждения из-за частичного чтения или записи) во всех случаях, кроме одного, в котором он произвольно ограничено аргументом count = , потому что в противном случае dd с радостью write () его вывод в блоках одинакового размера с теми, в которых его вводом было read () , пока он не прочитает () полностью через него. И даже это предупреждение верно только , когда указано bs = или obs = не указано , как следующее предложение в В спецификации указано:

  • Если операнд bs = expr не указан, или преобразование, отличное от sync , noerror или notrunc , ввод должен быть обработан и собран в полноразмерные блоки вывода до тех пор, пока не будет достигнут конец ввода.

Без аргументов ibs = и / или obs = это не имеет значения, потому что ibs и obs одинаковы размер по умолчанию. Однако вы можете получить явное о буферизации ввода, указав разных размеров для любого и не , указав bs = (потому что это имеет приоритет) .

Например, если вы это сделаете:

IN| dd ibs=1| OUT

...тогда POSIX dd будет write () кусками по 512 байт, собирая каждый отдельный байт read () в один выходной блок .

В противном случае, если вы сделаете ...

IN| dd obs=1kx1k| OUT

... POSIX dd будет read () максимум 512 байт за раз, но ] write () каждый выходной блок размером в мегабайт (ядро разрешает и, возможно, исключая последний - потому что это EOF) полностью, собирая входные данные в полноразмерных выходных блоков .

Также из спецификации:

  • count = n
    • Копировать только n входных блоков.

count = отображается на i? Bs = блоков,и поэтому для обработки произвольного ограничения на count = переносимо вам понадобятся два dd s. Наиболее практичный способ сделать это с двумя dd s - связать вывод одного с вводом другого, что, безусловно, помещает нас в сферу чтения / записи специального файла независимо от исходного типа ввода.

Канал IPC означает, что при указании [io] bs = аргументов, чтобы сделать это безопасно, вы должны сохранить такие значения в пределах установленного системой ограничения PIPE_BUF . POSIX утверждает, что ядро ​​системы должно гарантировать только атомарные read () и write () s в пределах PIPE_BUF , как определено в пределах . ч . POSIX гарантирует, что PIPE_BUF будет как минимум ...

  • {_ POSIX_PIPE_BUF}
    • Максимальное количество байтов, которое гарантированно будет атомарным при записи в канал.
    • Значение: 512

... (которое также является размером блока ввода-вывода по умолчанию dd по умолчанию) , но фактическое значение обычно составляет не менее 4k. В современной системе Linux это по умолчанию 64 КБ.

Итак, когда вы настраиваете свои процессы dd , вы должны делать это с коэффициентом блока на основе трех значений:

  1. bs = (obs = PIPE_BUF или меньше)
  2. n = общее желаемое количество прочитанных байтов
  3. count = n / bs

Например:

yes | dd obs=1k | dd bs=1k count=10k of=/dev/null
10240+0 records in
10240+0 records out
10485760 bytes (10 MB) copied, 0.1143 s, 91.7 MB/s

Вы должны синхронизировать i / ow / dd для обработки отсутствия поиска входы. Другими словами, сделайте буферы каналов явными, и они перестанут быть проблемой.Для этого нужен dd . Неизвестной величиной здесь является размер буфера да , но если вы заблокируете это до известной величины с другим dd , то небольшое умножение на основе информации может дать dd безопасно использовать для копирования данных (без риска повреждения из-за частичного чтения или записи) даже при произвольном ограничении ввода с count = с любым произвольным вводом введите в любой системе POSIX и не пропустите ни одного байта.

Вот фрагмент из спецификации POSIX :

  • ibs = expr
    • Укажите размер входного блока в байтах с помощью expr (по умолчанию 512 ) .
  • obs = expr
    • Укажите размер выходного блока в байтах с помощью expr (по умолчанию 512) .
  • bs = expr
    • Установите размеры входных и выходных блоков равными expr байтов, заменив ibs = и obs = . Если не указано никакого преобразования, кроме sync , noerror и notrunc , каждый входной блок должен копироваться на выход как единый блок без агрегирования коротких блоков.

Вы также найдете некоторые из этих объяснений лучше здесь .

3
09.02.2018, 18:45
1 ответ

в bash, используяcolumn

$ column -s $'\t' -t file.tsv
col1       col2 col2 col2  col3 col3  col4
col1       col2 col2       col3       col4 col4
col1 col1  col2 col2       col3       col4 col4 col4

column -tиспользует 2 пробела для разделения столбцов


С awk я бы написал

awk -F '\t' -v cols=4 '
    NR == FNR {
        for (i=1; i<=cols; i++) 
            if (NR == 1 || length($i) > w[i]) 
                w[i] = length($i)
        next
    }
    {
        for (i=1; i<=cols; i++) 
            printf "%-*s%s", w[i], $i, (i == cols ? ORS : FS) 
    }
' file.tsv file.tsv

Где я обрабатываю файл дважды :сначала, чтобы найти максимальную ширину для каждого столбца, а затем еще раз, чтобы переформатировать файл. Я использую вкладку, чтобы разделить столбцы в выводе.

col1            col2 col2 col2  col3 col3       col4
col1            col2 col2       col3            col4 col4
col1 col1       col2 col2       col3            col4 col4 col4
4
27.01.2020, 21:18

Теги

Похожие вопросы