Print a file's last modified date in Bash
Asked Answered
A

11

217

I can't seem to find how to print out the date of a file. I'm so far able to print out all the files in a directory, but I need to print out the dates with it.

I know I need to attach a date format with the echo of the entry, but all I can't find the correct format.

echo "Please type in the directory you want all the files to be listed"

read directory 

for entry in "$directory"/*
do
  echo "$entry"
done
Abadan answered 6/5, 2013 at 2:28 Comment(1)
read -p "Please type in the directory you want all the files to be listed" directoryRedeemable
T
172

You can use the stat command

stat -c %y "$entry"

More info

%y   time of last modification, human-readable
Troglodyte answered 6/5, 2013 at 2:28 Comment(4)
for entry in "$directory"/* do stat -c%y "$entry" done Doesn't work. Prints out stat: missing operand in terminalAbadan
Hm, could it be my unbuntu? Do you know what the requirements of using stat is?Abadan
Note that on OS X (Mac), it's stat -f "%m%t%Sm %N" filename (see man stat examples for more details)Spanjian
Note that on BSD the stat command has a different syntax. My case for FreeBSD: stat -f %Sm -t %F" "%R filename.Whichsoever
P
353

Isn't the 'date' command much simpler? No need for awk, stat, etc.

date -r <filename>

Also, consider looking at the man page for date formatting; for example with common date and time format:

date -r <filename> "+%m-%d-%Y %H:%M:%S"
Peppard answered 27/12, 2013 at 20:25 Comment(12)
Much simpler then using stat / more available.Pinkster
It looks like BSD (or at least OS X's) date's doesn't have this. Its -r is just used to provide a timestamp to format. You'll have to use GNU date to get this functionality.Ous
On OSX use: date stat -f "%Sm" -t "%m%d%H%M%y" "${1}"Planish
@Mich - I get stat no such file or directoryHare
On OS X 10.10 date -r <filename> works as advertised, although the man page doesn't describe any <filename> argument.Bog
is there a way to get more granular time than seconds?Brainless
yes @AlexanderMills you can just specify your format date -r <filename> "+%b %d %Y %T %Z"Prehension
No date -r on OS X 10.11, but gdate -r from GNU Core Utils works.Shortridge
In macOS 10.13 date [-r seconds | filename] is fully documented in the man page, and works as expected.Holy
I love this answer, particularly because date -r $FILE +%s.%N can provide more precision than stat -c%YFossorial
Piped: echo "${file}" | xargs date +%s -rSandalwood
How'd this change for directory?Yell
T
172

You can use the stat command

stat -c %y "$entry"

More info

%y   time of last modification, human-readable
Troglodyte answered 6/5, 2013 at 2:28 Comment(4)
for entry in "$directory"/* do stat -c%y "$entry" done Doesn't work. Prints out stat: missing operand in terminalAbadan
Hm, could it be my unbuntu? Do you know what the requirements of using stat is?Abadan
Note that on OS X (Mac), it's stat -f "%m%t%Sm %N" filename (see man stat examples for more details)Spanjian
Note that on BSD the stat command has a different syntax. My case for FreeBSD: stat -f %Sm -t %F" "%R filename.Whichsoever
U
34

Alternatively, you may try also :

date -r filename +"%Y-%m-%d %H:%M:%S"
Unsnarl answered 18/4, 2018 at 6:7 Comment(2)
This answer is a duplicate of https://mcmap.net/q/125372/-print-a-file-39-s-last-modified-date-in-bashNightjar
@UlysseBN no it's slightly different. He's advocating for a better date format.Khartoum
D
16

On OS X, I like my date to be in the format of YYYY-MM-DD HH:MM in the output for the file.

So to specify a file I would use:

stat -f "%Sm" -t "%Y-%m-%d %H:%M" [filename]

If I want to run it on a range of files, I can do something like this:

#!/usr/bin/env bash
for i in /var/log/*.out; do
  stat -f "%Sm" -t "%Y-%m-%d %H:%M" "$i"
done

This example will print out the last time I ran the sudo periodic daily weekly monthly command as it references the log files.


To add the filenames under each date, I would run the following instead:

#!/usr/bin/env bash
for i in /var/log/*.out; do
  stat -f "%Sm" -t "%Y-%m-%d %H:%M" "$i"
  echo "$i"
done

The output would was the following:

2016-40-01 16:40
/var/log/daily.out
2016-40-01 16:40
/var/log/monthly.out
2016-40-01 16:40
/var/log/weekly.out

Unfortunately I'm not sure how to prevent the line break and keep the file name appended to the end of the date without adding more lines to the script.


PS - I use #!/usr/bin/env bash as I'm a Python user by day, and have different versions of bash installed on my system instead of #!/bin/bash

D answered 1/5, 2016 at 7:21 Comment(1)
In case you haven't figured out the line break part, the -e flag is available for the echo program. Example usage could be: echo -e "$(stat -f %Sm -t %Y%m%d_%H%M%S $AFile)\t$AFile.". In your case it could be: echo -e "$(stat -f "%Sm" -t "%Y-%m-%d %H:%M" "$i")\t$i." `Colettacolette
B
7

Adding to @StevePenny answer, you might want to cut the not-so-human-readable part:

stat -c%y Localizable.strings | cut -d'.' -f1
Bit answered 6/5, 2013 at 2:33 Comment(0)
C
4

For the line breaks i edited your code to get something with no line breaks.

#!/bin/bash
for i in /Users/anthonykiggundu/Sites/rku-it/*; do
   t=$(stat -f "%Sm"  -t "%Y-%m-%d %H:%M" "$i")
   echo $t : "${i##*/}"  # t only contains date last modified, then only filename 'grokked'- else $i alone is abs. path           
done
Conure answered 13/5, 2016 at 8:35 Comment(0)
O
3

If file name has no spaces:

ls -l <dir> | awk '{print $6, " ", $7, " ", $8, " ", $9 }'

This prints as the following format:

 Dec   21   20:03   a1.out
 Dec   21   20:04   a.cpp

If file names have space (you can use the following command for file names with no spaces too, just it looks complicated/ugly than the former):

 ls -l <dir> | awk '{printf ("%s %s %s ",  $6,  $7, $8); for (i=9;   i<=NF; i++){ printf ("%s ", $i)}; printf ("\n")}'
Orientalism answered 6/5, 2013 at 2:51 Comment(5)
Ah, I see! That mostly works, except for the files with the spaces in the names. Is there a solution for that?Abadan
Actually, I tried it again, and it doesn't work... turns out I was trying out a directory that had file names without spaces. =/ Edited my answer belowAbadan
when you say it does not work, can you say what is the error? it works for me when i executed it on my system.Orientalism
I got a "no such file or directory".Abadan
That is because you passed a value of <dir> which does not exist....the code is perfectly fine.Orientalism
A
2

EDITED: turns out that I had forgotten the quotes needed for $entry in order to print correctly and not give the "no such file or directory" error. Thank you all so much for helping me!

Here is my final code:

    echo "Please type in the directory you want all the files to be listed with last modified dates" #bash can't find file creation dates

read directory

for entry in "$directory"/*

do
modDate=$(stat -c %y "$entry") #%y = last modified. Qoutes are needed otherwise spaces in file name with give error of "no such file"
modDate=${modDate%% *} #%% takes off everything off the string after the date to make it look pretty
echo $entry:$modDate

Prints out like this:

/home/joanne/Dropbox/cheat sheet.docx:2012-03-14
/home/joanne/Dropbox/Comp:2013-05-05
/home/joanne/Dropbox/Comp 150 java.zip:2013-02-11
/home/joanne/Dropbox/Comp 151 Java 2.zip:2013-02-11
/home/joanne/Dropbox/Comp 162 Assembly Language.zip:2013-02-11
/home/joanne/Dropbox/Comp 262 Comp Architecture.zip:2012-12-12
/home/joanne/Dropbox/Comp 345 Image Processing.zip:2013-02-11
/home/joanne/Dropbox/Comp 362 Operating Systems:2013-05-05
/home/joanne/Dropbox/Comp 447 Societal Issues.zip:2013-02-11
Abadan answered 6/5, 2013 at 3:18 Comment(0)
D
2

I wanted to get a file's modification date in YYYYMMDDHHMMSS format. Here is how I did it:

date -d @$( stat -c %Y myfile.css ) +%Y%m%d%H%M%S

Explanation. It's the combination of these commands:

stat -c %Y myfile.css # Get the modification date as a timestamp
date -d @1503989421 +%Y%m%d%H%M%S # Convert the date (from timestamp)
Demagogue answered 30/8, 2017 at 8:44 Comment(0)
C
0

To get the modification date of a file in the format YYYYMMDD_hhmm:

date -r <file> "+%Y%m%d_%H%M"

    20240119_1018

MODDATE=`date -r <file> "+%Y%m%d_%H%M"`

echo $MODDATE

    20240119_1018

This can also be done in a brute force way with

stat -c %y <file>

    2024-01-19 10:18:17.000000000 -0500

stat -c %y <file> | sed "s/^\(....\)-\(..\)-\(..\) \(..\):\(..\).*$/\1\2\3_\4\5/"

    20240119_1018

MODATE=`stat -c %y <file> | sed "s/^\(....\)-\(..\)-\(..\) \(..\):\(..\).*$/\1\2\3_\4\5/"`

echo $MODATE

    20240119_1018
Canonicals answered 2/3 at 22:56 Comment(0)
D
-2

You can use:

ls -lrt filename |awk '{printf "%02d",$7}'

This will display the date (a current day of a month) in 2 digits.

If between 1 to 9 it adds "0" prefix to it and converts to 01 - 09.

Hope this meets the expectation.

Dehnel answered 7/1, 2019 at 14:40 Comment(1)
It's an anti-pattern to parse ls output.Rhiamon

© 2022 - 2024 — McMap. All rights reserved.