1

If I last modified a file 5 minutes ago, is it possible to make ls-l output something like "5 mins" instead of the actual date/time?

Raffa
  • 32,237
B.Tanner
  • 2,636

4 Answers4

1

I use stat to get metadata info on the files. Some examples:

stat -c $'%y\t%n' * | sort -n

Output looks like this:

2020-01-27 11:52:25.681249958 +0200 CHANGELOG.md

Then to lookup a single file

stat CHANGELOG.md

and output looks like this:

  File: CHANGELOG.md
  Size: 94          Blocks: 8          IO Block: 4096   regular file
  Device: fd00h/64768d  Inode: 6029378     Links: 1
  Access: (0644/-rw-r--r--)  Uid: (  998/example)   Gid: (  998/example)
  Access: 2020-11-12 17:47:34.768793021 +0200
  Modify: 2020-01-27 11:52:25.681249958 +0200
  Change: 2020-11-12 17:47:02.282093672 +0200
  Birth: -

Otherwise you might need a small bash script to show you the difference between when the file was created and current time.

 LastUpdate="$(stat -c %Y myfile)"
 now="$(date +%s)"
 let diff="${now}-${lastUpdate}"
ognjen011
  • 1,319
1

This is a continuation of an earlier script used for parsing
ls -l with some enhancement:

#!/bin/bash

while read -r p c u g s e n; do [[ $p = total ]] && {
echo "$p $c" 1>&2; continue;
} x=$(($EPOCHSECONDS - e)) y=$((x / 60)) z=$((x % 60)) printf '%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\n'
"$p"
"$c"
"$u"
"$g"
"$s"
"$y minutes"
"$z seconds"
"$n" done < <(
ls -LApl --color=force
--time-style=+%s
--quoting-style=shell-escape "$@"
)
| column -t -R 2,5,6,7 -s $'\t' -o ' '

  • Thank you it hadn't occured to me that you could parse the output of ls -l in bash so easily. I already have a bash function that outputs a duration in seconds in the format I like, so I will start from this. $EPOCHSECONDS doesn't work for me though on 18.04 (bash 4.4) but I can use the appropriate date command. – B.Tanner Jan 21 '21 at 11:06
  • @B.Tanner think x=$(($(printf '%(%s)T') - e)) is a better choice than date –  Jan 21 '21 at 11:20
  • printf has the advantage of being builtin. –  Jan 21 '21 at 11:35
  • On my system (18.04 kubuntu) which printf shows an execuable at /usr/bin/printf, and which date shows an executable at /bin/date, whereas which cd and which shopt do not produce an output (and return an error code of 1). But date is 99k and printf is 51k :-O – B.Tanner Jan 21 '21 at 17:59
  • I think the order is alias, keyword, function, builtin, and file. but I'm not really sure. You can use type printf, builtin has the advantage of not needing any load time. time (printf '%(%s)T') vs time (date +%s) –  Jan 21 '21 at 18:53
  • think pico /usr/bin/which is an ordinary shell script, only searching the PATH. –  Jan 21 '21 at 19:19
  • 1
    Ah thank you...'type'! I wonder why printf is there on $PATH as an exectable file too then? I suppose non-bash shells might not have it as a builtin? – B.Tanner Jan 21 '21 at 19:25
0

One way:

You can make ls print modification time in seconds since epoch, like so:

ls -l --time-style="+%s"

Then pipe the ls output to awk to do the logic, like so:

ls -l --time-style="+%s" | awk -v now=$(date +%s) '{$6 = now - $6; d=int($6/60/60/24); h=int($6/60/60%24); m=int($6/60%60); s=int($6%60);$6 = "="d" Days "h" Hours "m" Mins "s" Secs ago="; print}' | column -t -s'='

Because the command line is long, here is a break-up which is basically the same but can be visually more contained:

ls -l --time-style="+%s" | \
awk -v now=$(date +%s) '{\
$6 = now - $6; \
d=int($6/60/60/24); \
h=int($6/60/60%24); \
m=int($6/60%60); \
s=int($6%60);\
$6 = "="d" Days "h" Hours "m" Mins "s" Secs ago="; print}' | column -t -s'='
  • -v now=$(date +%s) will assign the current time in seconds since epoch to now

  • $6 = now - $6 will calculate the time in seconds since file last modified.

  • d=int($6/60/60/24) will calculate the days.

  • h=int($6/60/60%24) will calculate remaining hours less than one day.

  • m=int($6/60%60) will calculate remaining minutes less than one hour.

  • s=int($6%60) will calculate remaining seconds less than one minute.

  • $6 = d" Days "h" Hours "m" Mins "s" Secs ago" will change the modification date to something like 2 Days 5 Hours 3 Mins 47 Secs ago.


Another way:

You can construct your own custom ls -l alternative in a bash script, like so:

#!/bin/bash

for f in * do p=$(stat -c "%A=%h=%U=%G=%s" "$f") m=$(date -r "$f" "+%s") n=$(date "+%s") l=$((n-m)) d=$((l/60/60/24)) h=$((l/60/60%24)) m=$((l/60%60)) s=$((l%60)) echo "$p= = =$d Days=$h Hours=$m Mins=$s=Secs= = =$f" | column -t -s'=' done

or make the output simpler and less time strict, like so:

#!/bin/bash

for f in * do p=$(stat -c "%A %h %U %G %s" "$f") m=$(date -r "$f" "+%s") n=$(date "+%s") l=$((n-m)) d=$((l/60/60/24)) h=$((l/60/60%24)) m=$((l/60%60)) s=$((l%60)) if (( $d >= 1 )) then t="$d Days" elif (( $h >= 1 )) then t="$h Hours" elif (( $m >= 1 )) then t="$m Mins" else t="$s Secs" fi echo "$p= = =$t= = =$f" | column -t -s'=' done


Notice on usage:

If you save either the above command or the above script in a file in your home directory, name the file lsl.sh and make it executable like so:

chmod +x ~/lsl.sh

you can add an alias like this:

alias lsl='bash ~/lsl.sh'

to your ~/.bashrc file so you can afterwords run the short command: `

lsl

from any directory and get the desired result.

Raffa
  • 32,237
0

Answering my own question here because this is what I actually ended up doing.

I could not get any satisfactory results using anything that parsed the output of ls -l into a word stream (bash, awk, column etc) because a) filenames with spaces in messed up, and b) ls -l's aligned columns messed up (for example, right-aligned filesizes). ls -l | column -t shows both problems at once.

I will get shot down for the inefficiency in this, but this is my eventual script that uses sed to replace parts of the output of ls -l maintaining column width:

day0=`date                     +"%b %_d"`
day1=`date --date "1 day  ago" +"%b %_d"`
day2=`date --date "2 days ago" +"%b %_d"`
day3=`date --date "3 days ago" +"%b %_d"`
day4=`date --date "4 days ago" +"%b %_d"`
day5=`date --date "5 days ago" +"%b %_d"`
day6=`date --date "6 days ago" +"%b %_d"`

min0=date +&quot;%H:%M&quot; min1=date --date &quot;1 minute ago&quot; +&quot;%H:%M&quot; min2=date --date &quot;2 minutes ago&quot; +&quot;%H:%M&quot; min3=date --date &quot;3 minutes ago&quot; +&quot;%H:%M&quot; min4=date --date &quot;4 minutes ago&quot; +&quot;%H:%M&quot; min5=date --date &quot;5 minutes ago&quot; +&quot;%H:%M&quot; min6=date --date &quot;6 minutes ago&quot; +&quot;%H:%M&quot; min7=date --date &quot;7 minutes ago&quot; +&quot;%H:%M&quot; min8=date --date &quot;8 minutes ago&quot; +&quot;%H:%M&quot; min9=date --date &quot;9 minutes ago&quot; +&quot;%H:%M&quot;

ls -lh --color=force --quoting-style=shell-escape "$@"|sed "
/$day6 (.[0-9]:[0-9][0-9])/ s/$day6/6 days/; t /$day5 (.[0-9]:[0-9][0-9])/ s/$day5/5 days/; t /$day4 (.[0-9]:[0-9][0-9])/ s/$day4/4 days/; t /$day3 (.[0-9]:[0-9][0-9])/ s/$day3/3 days/; t /$day2 (.[0-9]:[0-9][0-9])/ s/$day2/2 days/; t /$day1 (.[0-9]:[0-9][0-9])/ s/$day1/yesday/; t /$day0 (.[0-9]:[0-9][0-9])/ s/$day0/ today/; T s/$min0/ now/; t s/$min1/1 min/; t s/$min2/2 min/; t s/$min3/3 min/; t s/$min4/4 min/; t s/$min5/5 min/; t s/$min6/6 min/; t s/$min7/7 min/; t s/$min8/8 min/; t s/$min9/9 min/; t "

Sample output of /var/log/syslog*:

-rw-r----- 1 syslog adm    9240  today   now /var/log/syslog
-rw-r----- 1 syslog adm 1279965  today 8 min /var/log/syslog.1
-rw-r----- 1 syslog adm   51750 2 days 14:12 /var/log/syslog.2.gz
-rw-r----- 1 syslog adm   14768 3 days 10:59 /var/log/syslog.3.gz
-rw-r----- 1 syslog adm    7767 4 days 10:04 /var/log/syslog.4.gz
-rw-r----- 1 syslog adm  119295 5 days 09:49 /var/log/syslog.5.gz
-rw-r----- 1 syslog adm   33450 6 days 13:06 /var/log/syslog.6.gz
-rw-r----- 1 syslog adm   21372 Jan 25 11:12 /var/log/syslog.7.gz

(not sure why log appears here in red; it doesn't on my terminal.)

This is only used from the command line so all those date commands don't matter, in fact I don't notice any delay at all.

Update:

time output for `ls -l /var/log/syslog*':

real    0m0.002s
user    0m0.002s
sys     0m0.000s

time output for for my new script:

real    0m0.019s
user    0m0.018s
sys     0m0.003s
B.Tanner
  • 2,636