17th October 2018
Formatting file listings with "ls -l" and "stat"
Psst! This article isn't really about ls -l
One of the first tools that a newcomer to Unix or Linux learns is the
ls command. It lists files; by default,
it lists all of the files (apart from those which begin with a period, such as
.bash_profile) in the current directory. And
it formats them in convenient columns, organised to match the size of your terminal window:
steve@linux:/tmp/eg$ ls 17abc path.xcf tree.xcf burton-colour.odp profile.xfg walks git.txt redstar.sun wargames.jpg logo.xcf
The second thing people learn about
ls is that you can use
ls -l to give a long listing. This shows the owner, file type, and timestamp (which
is normally the modification time). And then the third thing is that
ls -ltr orders them by that timestamp. The
-r reverses the order, so that older files are listed at the top, with the newest file at the bottom.
What people often only casually notice, however, is that
ls has two different ways of displaying the timestamp of a file:
steve@linux:/tmp/eg$ ls -ltr drwxr-xr-x 2 steve steve 4096 Jul 10 2016 walks drwxr-xr-x 11 steve steve 4096 Mar 3 2018 17abc drwxr-xr-x 3 steve steve 4096 Sep 27 23:14 tmp -rw-r--r-- 1 steve steve 361402 Oct 17 21:39 wargames.jpg . . .
The first two files (which happen to be directories, but in *nix, everything is a file) are in the format "Month Day Year", but the other two are in the format "Month Day Time." The older a file is, the less relevant its actual time of modification becomes. And it saves a little bit of space to choose one format or the other. But what many people assume is that this changeover happens when a file is more than a year old.
But that wouldn't really work too well. If today was the 1st of January, then pretty much every file you listed would be in the "Month Day Year" format, and you wouldn't see the hours and minutes even on a file you edited yesterday. That would be pretty annoying.
If it was anything over 12 months old, then files around today's date would start to look a bit confusing. So GNU's
ls, at least, uses a cut-off date of 6 months ago.
info '(coreutils) ls invocation':
A timestamp is considered to be "recent" if it is less than six months old, and is not dated in the future.
This is demonstrated in the listing above; this article was written on 17th October 2018, so the two newest files are less than six months old. They are shown with the actual modification
time. But the "
17abc" directory is from March 2018, so it is just over 7 months old. It is listed in the same format as the 2016 "
What this article is really about
Parsing the output from
ls is a really bad idea; even when you're doing it by eye. Doing it in a shell script is totally unnecessary, when you have the
command at your fingertips.
steve@linux:/tmp/eg$ stat 17abc File: ‘17abc’ Size: 4096 Blocks: 8 IO Block: 4096 directory Device: fd05h/64773d Inode: 651553 Links: 11 Access: (0755/drwxr-xr-x) Uid: ( 1000/ steve) Gid: ( 1000/ steve) Access: 2018-03-03 07:34:00.000000000 +0000 Modify: 2018-03-03 07:34:00.000000000 +0000 Change: 2018-10-17 21:51:15.213895227 +0100 Birth: - steve@linux:/tmp/eg$
This shows you in a much more detailed and accessible format the metadata about the file. However, there is an even better way.
stat -c takes formatting
strings which allow you to select specific pieces of data about the file.
%y formatting string selects the modification time.
steve@linux:/tmp/eg$ stat -c %y 17abc 2018-03-03 07:34:00.000000000 +0000 steve@linux:/tmp/eg$
%A %U %n formatting string selects the access permissions, the owner's name, and the file's name.
steve@linux:/tmp/eg$ stat -c "%A %U %n" 17abc drwxr-xr-x steve 17abc steve@linux:/tmp/eg$
man stat for the full list of formatting strings. You can derive a lot of information from a file, and you can also (like
printf and other tools)
include your own text in the output:
steve@linux:/tmp/eg$ stat -c "The file %n has %A permissions and is owned by %U (UID %u)" 17abc The file 17abc has drwxr-xr-x permissions and is owned by steve (UID 1000) steve@linux:/tmp/eg$
You can (and should) use the
stat command in your shell scripts whenever you need to get metadata about a file. It is a much easier way than parsing the output
ls or other such utilities.
stat gives you a tremendous amount of flexibility.
However, it is not available in all Unix variants, although every GNU/Linux system should have it included, as is is part of the GNU 'coreutils' package.
You can buy the content of this tutorial as a PDF to download to all of your devices!
You can mail me with this form. If you expect a reply, please ensure that the address you specify is valid. Don't forget to include the simple addition question at the end of the form, to prove that you are a real person!