Issue
I want to convert the 5th column in this command output to human readable format. For ex if this is my input :
-rw-rw-r-- 1 bhagyaraj bhagyaraj 280000 Jun 17 18:34 demo1
-rw-rw-r-- 1 bhagyaraj bhagyaraj 2800000 Jun 17 18:34 demo2
-rw-rw-r-- 1 bhagyaraj bhagyaraj 28000000 Jun 17 18:35 demo3
To something like this :
-rw-rw-r-- 280K demo1
-rw-rw-r-- 2.8M demo2
-rw-rw-r-- 28M demo3
I tried this command, but this will return only the file size column.
ls -l | tail -n +2 |awk '{print $5 | "numfmt --to=si"}'
ls
is just for example my use case is very huge and repeated execution must be avoided
Any help would be appreciated :)
Solution
Just use -h --si
-h, --human-readable with -l and -s, print sizes like 1K 234M 2G etc.
--si likewise, but use powers of 1000 not 1024
So the command would be
ls -lh --si | tail -n +2
If you don't use ls
and the command you intend to run doesn't have an option similar to -h --si
in ls
then numfmt
already has the --field
option to specify which column you want to format. For example
$ df | LC_ALL=en_US.UTF-8 numfmt --header --field 2-4 --to=si Filesystem 1K-blocks Used Available Use% Mounted on udev 66M 0 66M 0% /dev tmpfs 14M 7.2K 14M 1% /run /dev/mapper/vg0-lv--0 4.1G 3.7G 416M 90% / tmpfs 5.2K 4 5.2K 1% /run/lock /dev/nvme2n1p1 524K 5.4K 518K 2% /boot/efi
Unfortunately although numfmt
does try to preserve the columnation, it fails if there are some large variation in the line length after inserting group separators like you can see above. So sometimes you might still need to reformat the table with column
df | LC_ALL=en_US.UTF-8 numfmt --header --field 2-4 --to=si | column -t -R 2,3,4,5
The -R 2,3,4,5
option is for right alignment, but some column
versions like the default one in Ubuntu don't support it so you need to remove that
Alternatively you can also use awk
to format only the columns you want, for example column 5 in case of ls
$ ls -l demo* | awk -v K=1e3 -v M=1e6 -v G=1e9 'func format(v) { if (v > G) return v/G "G"; else if (v > M) return v/M "M"; else if (v > K) return v/K "K"; else return v } { $5 = format($5); print $0 }' | column -t -rw-rw-r-- 1 ph ph 280K Jun 18 09:23 demo1 -rw-rw-r-- 1 ph ph 2.8M Jun 18 09:24 demo2 -rw-rw-r-- 1 ph ph 28M Jun 18 09:23 demo3 -rw-rw-r-- 1 ph ph 2.8G Jun 18 09:30 demo4
And column 2, 3, 4 in case of df
# M=1000 and G=1000000 because df output is 1K-block, not bytes $ df | awk -v M=1000 -v G=1000000 'func format(v) { if (v > G) return v/G "G"; else if (v > M) return v/M "M"; else return v } { # Format only columns 2, 3 and 4, ignore header if (NR > 1) { $2 = format($2); $3 = format($3); $4 = format($4) } print $0 }' OFS="\t" | column -t Filesystem 1K-blocks Used Available Use% Mounted on udev 65.8273G 0 65.8273G 0% /dev tmpfs 13.1772G 7M 13.1702G 1% /run /dev/mapper/vg0-lv--0 4073.78G 3619.05G 415.651G 90% / tmpfs 65.8861G 0 65.8861G 0% /dev/shm tmpfs 5.12M 4 5.116M 1% /run/lock tmpfs 65.8861G 0 65.8861G 0% /sys/fs/cgroup /dev/nvme2n1p2 999.32M 363.412M 567.096M 40% /boot
Answered By - phuclv Answer Checked By - Marilyn (WPSolving Volunteer)