Linux: форматирование вывода потока (канала) с помощью столбца? (размер файла не определен)

#linux #formatting #stream #stdout

#linux #форматирование #поток #стандартный вывод

Вопрос:

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

 $ echo "1 12 123 1234 1 12 123 1234 " | column -t
1  12  123  1234  1  12  123  1234
  

.. однако, если я попытаюсь имитировать «бесконечный» поток:

 $ while true; do echo "1 12 123 1234 1 12 123 1234 "; sleep 1; done | column -t
^C
  

… ответа просто нет, пока не будет выполнен выход с помощью Ctrl-C.

(Обратите внимание, что while эта штука предназначена только для имитации чтения бесконечного потока с устройства, как в ‘ cat /dev/ttyUSB0 ‘)

Это наводит меня на мысль, что, даже если column по умолчанию должен приниматься стандартный ввод, для работы ему нужен «полный» и завершенный файл (то есть с определенным размером файла); а в случае «бесконечного» потока это не так — поэтому он никогда ничего не выводит.

Есть предложения о том, как я мог бы добиться форматирования столбца в этом контексте? РЕДАКТИРОВАТЬ: Необязательно должна быть column программа; подойдет все остальное, что форматирует текст в столбцы (но, боюсь, например, awk также нужен полный файл)…

Заранее спасибо,
Ура!

Комментарии:

1. Скорее всего, столбец должен прочитать все входные данные, чтобы решить, какой ширины сделать каждый столбец. Таким образом, вы не можете использовать его с «бесконечными» потоками, иначе он в конечном итоге поглотит всю память.

2. Спасибо за подтверждение @Keith — Я предполагаю, что это так, и column здесь неприменимо; но существуют ли альтернативные инструменты, которые работали бы «на строку» вместо «на файл»? Я предполагаю, что в этом случае количество столбцов и ширина столбца должны быть указаны априори, но для моего использования это нормально.. Приветствия!

3. Вместо этого вы могли бы передать его в sed и заменить пробелы табуляциями, а терминалы tabstops отформатировать его в столбцы. ... | sed -e 's/[ ] /t/g'

4. Спасибо за это, @Keith — sed кажется, что с этими «бесконечными» потоками все работает нормально; Я бы предпочел «реальные столбцы», поскольку это числовые данные, поэтому я хотел бы выровнять их по правой границе «слова»; тогда как вкладки выравниваются по левому краю…. Но все равно, вкладки намного лучше, чем раньше 🙂 Приветствия!

5. @Keith: ты опередил меня, только что закончил редактировать мой другой пост, чтобы предложить sed 🙂

Ответ №1:

Я тоже разочаровался в column из-за невозможности потоковой передачи, а код sdaau — из-за неспособности измерить мои столбцы. Итак, вот исправление обеих этих проблем. Возможно, это не очень эффективно, но в любом случае это просто для отладки. У меня это есть в моей папке ~ / bin как pcol (обязательно укажите chmod x):

 #!/usr/bin/env python
import sys

sep = ','
gutter = 2
for arg in sys.argv:
    if arg.startswith('-s'):
        sep = arg[2:]
    elif arg.startswith('-g'):
        gutter = int(arg[2:])

widths = []
while True:
    raw = sys.stdin.readline()
    line = raw.strip('').strip('n')
    vals = line.split(sep)
    if len(vals) > len(widths):
        widths = [0] * len(vals)

    widths = [max(len(val)   gutter, width) for val, width in zip(vals, widths)]
    metaformat = '%%%ds' * len(widths)
    format = metaformat % tuple(widths)
    print format % tuple(vals)
  

Комментарии:

1. Большое спасибо за это, @chbrown — только что попробовал » while true; do let "k=$RANDOM % 800"; echo "1 12 $k 1234 1 12 123 $RANDOM "; sleep 1; done | python pcol.py -s' ' -g3 «, и все работает отлично 🙂 Перенес accept тоже; еще раз спасибо — ура!

Ответ №2:

Ответа нет, потому что ваша вторая команда создает бесконечный цикл, а затем запрашивает, чтобы после завершения результат был передан в column -t. Поскольку цикл никогда не завершается, column -t ничего не делает. Я не уверен, чего вы пытаетесь достичь, но вариант 2nd command, который выдает вывод с интервалом в одну секунду (я предполагаю, что вы этого хотите), заключается в следующем:

 while true; do echo "1 12 123 1234 1 12 123 1234 " | column -t; sleep 1; done
  

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

 echo "1 12 123 1234 1 12 123 1234 " | sed 's/ /t/g'
  

Комментарии:

1. Привет @user507078 — спасибо за это, но я использовал while конструкцию просто для имитации бесконечного потока, как при чтении потока с устройства, как в cat /dev/ttyUSB0 — где данные отображаются каждую секунду…

Ответ №3:

Хорошо, благодаря ответам здесь, мне удалось создать скрипт на python, который будет это делать; очевидно, вы должны знать (и вводить в скрипт) формат столбцов априори; вот сценарий, columnizeline.py :

 #!/usr/bin/env python

import sys;

#below no work:
#print sys.stdin;
#for line in sys.stdin:
#   sline=line.split(' ')
#   print sline

while 1:
  next = sys.stdin.readline()
  ns = next.strip('').split(' ') # remove null char
  ns.pop() # remove the last entry in the list, it is 'n'
  #~ nextf = "%4s %4s %4s %4s %4s %4s %4s %4s" % (ns[0], ns[1], ns[2], ns[3], ns[4], ns[5], ns[6], ns[7])
  nextf=""
  nsc = ns[0:6] # first 6 elements only
  for nsi in nsc:
    nextf = "%s%5s" % (nextf, nsi)
  print nextf
  

… и вот небольшой тест:

 $ while true; do echo "1 12 123 1234 1 12 123 1234 "; sleep 1; echo "100 1 123 12 1 12 123 1234 "; sleep 1; done | ./columnizeline.py 
   1   12  123 1234    1   12  123 1234
 100    1  123   12    1   12  123 1234
   1   12  123 1234    1   12  123 1234
 100    1  123   12    1   12  123 1234
   1   12  123 1234    1   12  123 1234
 100    1  123   12    1   12  123 1234
^CTraceback (most recent call last): [...]
  

Приветствия!