Hey guys,

I have this script that does count one year of files, 2014, but when it comes to this year, everything messes up.
How could I count properly for each year in the same script ?

In the attached screenshot it's obvious that I would only need 2014 - all of the months and from 2015 only January, but .... how ?

Thanks in advance!

ls -la |
awk -v year="$(date "+%Y")" 'BEGIN {
        split("Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec", month, " ")
        for (i=1; i<=12; i++){ 
            mdigit[month[i]]=i
        }
    }
!/^-/{next}
$8 ~ /:/{$8=year} {
  dat=$8 sprintf("%02d",mdigit[$6]) sprintf("%02d",$7)
  a[dat]++
}
END{for(i in a){print i, a[i]|"sort"}}'

Dani AI

Generated

had the right diagnosis: the short ls -l date column hides the year for recent files, which breaks any parser that expects a year. 's idea to show full timestamps and 's suggestion to avoid parsing ls are both correct — the reliable solution is to read file timestamps directly and aggregate them.

A concise, robust approach on GNU systems (Linux) — count files grouped by year or by year-month:

# per-year (YYYY)
find . -type f -printf '%TY\n' | sort | uniq -c | sort

# per-month (YYYY-MM)
find . -type f -printf '%TY-%Tm\n' | sort | uniq -c | sort

To count files modified in a specific year without parsing output, use date-range tests (GNU find):

# files modified in 2015
find . -type f -newermt '2015-01-01' ! -newermt '2016-01-01' | wc -l

Portability notes and pitfalls: -printf and -newermt are GNU extensions. On macOS/BSD use stat to get formatted timestamps, then aggregate with awk/sort/uniq. Example pattern (BSD/macOS stat):

find . -type f -exec stat -f '%Sm %N' -t '%Y-%m' {} + \
  | awk '{print $1}' | sort | uniq -c | sort

Also consider recursion (add -maxdepth 1 on GNU find to limit to current dir) and whether symlinks or directories should be counted. These approaches avoid brittle text-parsing of ls and give correct counts across year boundaries.

Recommended Answers

All 4 Replies

Because recent modified files do not have year number display in the list. You may try ls -la --full-time and will have to update some of your display.

#!/bin/bash
year=$(date +"%Y")
if [ $# -gt 0 ] ; then
  year=$1
fi
echo $year
list=$(ls -la --full-time | awk -v pattern="$year" '$6 ~ pattern { printf ("%s %s ", $6, $9) }')
echo $list

The above is a quick & dirty test of how to capture all files that were modified at a given year (or the current year if no argument is passed). Column 6 in the list is now yyyy-mm-dd instead of spelling out month name.

commented: great +5

this also is why 'ls' should be avoided in shell script; instead use 'stat'.

Thank you Taywin, you solution was the good one, I've splitted the output in PHP and transformed it in array and counted the same occurences and it worked well!

Because recent modified files do not have year number display in the list. You may try ls -la --full-time and will have to update some of your display.

>     #!/bin/bash
>     year=$(date +"%Y")
>     if [ $# -gt 0 ] ; then
>     year=$1
>     fi
>     echo $year
>     list=$(ls -la --full-time | awk -v pattern="$year" '$6 ~ pattern { printf ("%s %s ", $6, $9) }')
>     echo $list

The above is a quick & dirty test of how to capture all files that were modified at a given year (or the current year if no argument is passed). Column 6 in the list is now yyyy-mm-dd instead of spelling out month name.

even better : use 'find' it'll do it at once.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.