Как ls -l так аккуратно форматирует вывод?


Ответы:


34

Исходный код lsдоступен для просмотра онлайн на GNU Savannah . В большинстве случаев вычисляется требуемая максимальная ширина (например, с использованием mbswidthфункции для текста), а затем используются классические printfспецификаторы формата функции C и некоторые ручные отступы. Смотрите, например, функции format_user_or_group()и gobble_file().

TL; ДР: нет "магии", просто много грубых вычислений.


Если вам нужны такие аккуратные таблицы для собственного вывода, используйте column:

$ grep -vE '^#' /etc/fstab
UUID=cdff3742-9d03-4bc1-93e3-ae50708474f2 /               ext4    errors=remount-ro 0       1
/dev/mapper/lvmg-homelvm /home           btrfs   defaults,compress=lzo,space_cache,relatime 0       2
UUID="bb76cd0d-ae1d-4490-85da-1560c32679cd" none    swap sw 0 0
UUID="a264b1b1-cf82-40aa-ab9e-a810cfba169a" /home/muru/arch     btrfs defaults,compress=lzo,space_cache,relatime 0       2

$ grep -vE '^#' /etc/fstab | column -t
UUID=cdff3742-9d03-4bc1-93e3-ae50708474f2    /                ext4   errors=remount-ro                           0  1
/dev/mapper/lvmg-homelvm                     /home            btrfs  defaults,compress=lzo,space_cache,relatime  0  2
UUID="bb76cd0d-ae1d-4490-85da-1560c32679cd"  none             swap   sw                                          0  0
UUID="a264b1b1-cf82-40aa-ab9e-a810cfba169a"  /home/muru/arch  btrfs  defaults,compress=lzo,space_cache,relatime  0  2

4
Учитывая, что вы использовали / etc / fstab в качестве примера, я не могу не предложить findmnt --fstab. Пакет util-linux даже поставляется с библиотекой "libsmartcols" (ранее libtt), которую он использует в findmnt, lsblk и т. Д. Для печати выровненной таблицы.
Гравитация

@ Grawity приятно. Я использовал findmntраньше, но я никогда не понимал, что это может сделать это тоже.
Муру

Также полезно знать: в Ubuntu / debian /bin/lsвходит в состав пакета (GNU) coreutils. Вы можете найти это, запустив dpkg-query -S /bin/ls. Как только вы узнаете имя пакета, вы можете скачать любой точный исходный код любого пакета Ubuntu, из которого apt-get source <package_name>
собран

17

В дополнение к ответу @muru , здесь есть часть исходного кода, которая рассчитывает widthправильное обоснование вывода. :

static void
format_user_or_group (char const *name, unsigned long int id, int width)
{
  size_t len;

  if (name)
    {
      int width_gap = width - mbswidth (name, 0);
      int pad = MAX (0, width_gap);
      fputs (name, stdout);
      len = strlen (name) + pad;

      do
        putchar (' ');
      while (pad--);
    }
  else
    {
      printf ("%*lu ", width, id);
      len = width;
    }

  dired_pos += len + 1;
}

Он использует printf ("%*lu ", width, id);. ПРИМЕЧАНИЕ: спецификатор переменной ширины поля '*'

В этом случае невозможно предсказать, какая ширина поля нам понадобится при ls -lвыполнении, т. Е. Имена каталогов могут различаться по длине. Это означает, что сама ширина поля должна быть переменной , для которой программа будет вычислять значение .

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

Например, предположим, что текущее значение ширины равно 5. Оператор:

printf ("%*d%*d\n", width, 10, width, 11);

напечатает: (обратите внимание на интервал)

   10   11

widthЗдесь scontext_width, вычисляются gooble_file, с другой функцией я уже говорил.
Муру
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.