Get metada of file with portable way
Published on: 2023-10-19
Try to use command stat
with portable way
The command stat
is not POSIX and if you'd like to use same syntax
on UNIX machines as macOS, *BSD or Linux you have a problem. The interface is different
for BSD derivates and Linux world. The reason is that BSD comes from AT&T code and
Linux uses GNU coreutils which has some differences.
I met this problem when I wanted to get and check modification time of files.
If you want to format output to show only modification time with stat
comes from GNU/coreutils you'll write:
$ stat -c %Y file.txt
,but if you use stat
from BSD, then:
$ stat -f %m file.txt
You can see that stat
is different for both the option
and formatting character
.
Hack with awk
or grep
Fortunately the BSD version of stat
contains option -x
, which
caused the output will be same as in Linux. Thanks to that we can use awk
or grep
to get modification of timestamp.
grep
$ stat -x file.html | grep -i modify | cut -c 9-
awk
$ stat -x file.html | awk '/Modify:/ {printf $0}' | cut -c 9-
This approach has several drawbacks.
- you get modify time in format which is difficult to use for comparisons for example
- this output gives you only one type of time format and other format has to be get by other way
- you have to distinct if you use command
stat
on Linux or BSD derivate, because the option-x
can be used only in BSD derivates
Summary
It is not recommended easy portable way how to get modification time.Find out which type of stat
is used
Other approach is to find out which version of stat
is used and pass
suitable option and formatting character to the command. See example below to get
modification timestamp.
# GNU coreutils have option --version
if $(stat --version &>/dev/null)
then
mod_time_fmt="-c %Y"
else
mod_time_fmt="-f %m"
fi
By the code above we'll create portable version of stat
. Except for example solaris which does not contain
command stat
at all.
Same approach can be used when we was hacking with awk
or grep
, but here we get timestamp in seconds,x
which can be easily compared.
Same approach can be done with type of system, run uname
to get information if platform is Linux, Darwin(macOS) or BSD.
Use language for scripting as Perl
or Python
If you make something difficult or complicated you should leave scripting in shell and instead use language which was created for or language which is more suitable to achieve your goal. Perl and Python are scripting languages which are found on most systems (their scripts are very portable) and their syntax is much more friendly then shell scripting. They should contains any ordinary function which you need to get info about files.
If you still want to use only shell script you can use oneline call from shell script with scripting language.
Run Perl or Python code in shell script can be done with run the certain interpreter with option -e
resp. -c
.
$ file=path/to/file.txt
$ perl -e "print((stat(\"$file\"))[9])"
$ python -c "import os; print(os.stat(\"$file\").st_mtime, end='')"
Check if one file is newer then other with POSIX
There is one POSIX solution to get information if FILE1 is newer than FILE2 (FILE1 -nt FILE2
).
The solution below is described in FreeBSD documentation.
$ test -n "$(find -L -- FILE1 -prune -newer FILE2 2>/dev/null)"
Get modification time with date
command
Unfortunately it is not POSIX solution, but it can be used on Linux and macOS.
Command date
can show modification date with option -r
. Other nice feature of date
is formatting the output of time with leading plus character +
. After plus char you specify wanted output format. See example below.
$ date -r file.txt +%Y-%m-%d
2023-10-20
$ date -r file.txt +%Y/%m
2023/10