RSS Feed Share on Twitter

All Shell Scripting Tips

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

Showing Dates

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.

From 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 "walks" directory.

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 stat 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.

The %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$ 

The %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$ 

See 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$ 

Summary

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 of 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!

Contact

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!