How does ls -l format its output so neatly?
Solution 1:
The source code of ls
is available for browsing online on GNU Savannah. In most cases, the required maximum width is computed (for example, using the mbswidth
function for text), and then uses the classic C printf
function format specifiers and some manual padding. See, for example, the functions format_user_or_group()
, and gobble_file()
.
TL; DR: there's no "magic", just a lot of grunt computation.
If you want such neat tables for your own output, use 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
Solution 2:
In addition to @muru 's answer, here is the part of the source code which calculates width
for right justification of output. :
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;
}
It uses, printf ("%*lu ", width, id);
. NOTE : variable field width specifier ‘*’
In this case, it cannot be predicted how large a field width we will need when ls -l
is executed, i.e, The names of directories may vary in length . This implies that the field width itself needs to be a variable, for which the program will compute a value.
C uses an asterisk in the position of the field width specifier to indicate to printf that it will find the variable that contains the value of the field width as an additional parameter.
For instance, assume that the current value of width is 5. The statement:
printf ("%*d%*d\n", width, 10, width, 11);
will print: (note the spacing)
10 11