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?
4 Answers
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 ' '
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}"
- 1,403
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 tonow$6 = now - $6will 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.
- 34,963
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 +"%H:%M"
min1=date --date "1 minute ago" +"%H:%M"
min2=date --date "2 minutes ago" +"%H:%M"
min3=date --date "3 minutes ago" +"%H:%M"
min4=date --date "4 minutes ago" +"%H:%M"
min5=date --date "5 minutes ago" +"%H:%M"
min6=date --date "6 minutes ago" +"%H:%M"
min7=date --date "7 minutes ago" +"%H:%M"
min8=date --date "8 minutes ago" +"%H:%M"
min9=date --date "9 minutes ago" +"%H:%M"
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
- 2,685