List files with line count and date

6,746

Solution 1

Here is something with find + wc + date.

find . -maxdepth 1 -exec sh -c '[ -f "$0" ] && \
  printf "%6s\t\t%s\t%s\n" "$(wc -l<"$0")" "$(date -r "$0")" "$0"' {} \;

Instead of date -r one can also use for example stat -c%y.

The output looks like this:

   394      Thu Oct 16 22:38:14 UTC 2014    ./.zshrc
     7      Thu Oct 30 11:19:01 UTC 2014    ./tmp.txt
     2      Thu Oct 30 06:02:00 UTC 2014    ./tmp2.txt
    40      Thu Oct 30 04:16:30 UTC 2014    ./pp.txt

Using this as starting point one can create a function which accepts directory and pattern as parameters:

myls () { find "$1" -maxdepth 1 -name "$2" -exec sh -c '[ -f "$0" ] && \
  printf "%6s \t\t%s\t%s\n" "$(wc -l<"$0")" "$(date -r "$0")" "$0"' {} \;; }

After that myls /tmp '*.png' will list only images from /tmp (notice single quotes around pattern to prevent shell from expanding a glob operator *).

Solution 2

The find-based solutions look the most elegant, but just for fun here are a couple of other ways to attack this.

This one uses sed & head to clean up the output of wc, then uses join to combine that to the output of stat, using the file name as the join field.

pat="A*";join -1 2 -2 1 -t ' ' <(wc -l $pat|head -n-1|sed 's/^[ ]*//') <(stat -c '%n %y' $pat) | awk '{printf "%-20s %6s %s %s %s\n",$1,$2,$3,$4,$5}'

And a simpler one that uses paste, with awk again tidying up the columns and also checking that the file names match.

pat="A*";paste -d ' ' <(wc -l $pat) <(stat -c '%n %y' $pat) | awk '$2==$3{printf "%6s %s %s %s\n", $1, $4, $5, $2}'

However, if the names don't match (IOW the file lists change while this command is running) then the errors are invisible. But this version reports the errors:

pat="A*";paste -d ' ' <(wc -l $pat) <(stat -c '%n %y' $pat) | awk '$2==$3{printf "%6s %s %s %s\n", $1, $4, $5, $2;next};{print "Error:" $0}'

Of course, that one will print an error message for the final line, but that's easy enough to fix. Or ignore. :)

Share:
6,746

Related videos on Youtube

John Reid
Author by

John Reid

Updated on September 18, 2022

Comments

  • John Reid
    John Reid over 1 year

    I want to be able to list files showing the number of lines the each file has and the date. I can happily get the line count using wc -l *. Not a problem. I can get the date using ls -l.

    Is there a way to combine the two commands to give me a single output in columns?

  • slm
    slm over 9 years
    Explain what this is doing and how it works!
  • John Reid
    John Reid over 9 years
    Unfortunately wc dumps a new line which is being left behind.
  • user8973106
    user8973106 over 9 years
    I added tr to remove the "\n"
  • slm
    slm over 9 years
    FYI, pay special attn to Jimmij's comment about using stat -c%y. You're running date on every file using the former command, date -r. Otherwise +1, this is a good solution to the Q.
  • John Reid
    John Reid over 9 years
    Ah I missed it, sorry. It's not working for a list of files now though as it removes all of the line breaks.
  • John Reid
    John Reid over 9 years
    Great answer. I changed date to (date -r "$0" -%x) to give me something to import into a spreadsheet. Exactly what I needed and later I'll have a look at this more in depth.
  • Jakob Bennemann
    Jakob Bennemann over 9 years
    This seems so unnecessary given the find solution proposed above. This solution not only requires three actual commands, but it also uses a file on the system.
  • jimmij
    jimmij over 9 years
    @JohnReid I've changed original post a little, removed unnecessary variables, and added function for patterns. You may want to take a look. @slm you are right that one can do stat and wc on the whole list find ... {} + (if this is what you are saying), yes that would be for sure faster, but on the other hand more complicated since one would need to deal with loop over arrays later on (at least as I see it).
  • G-Man Says 'Reinstate Monica'
    G-Man Says 'Reinstate Monica' over 9 years
    Why would you choose to use a temporary file when all you need to do is pipe the output of the awk into tr?
  • G-Man Says 'Reinstate Monica'
    G-Man Says 'Reinstate Monica' over 9 years
    (1) I realize that the question says "list files", but, if there's only one file in the directory, wc will not output a "total" line, and so the head will discard the line count of the one existing file. (2) This breaks if filenames contain newlines. (3) This breaks if filenames contain spaces, because you say $file instead of "$file". You should always quote all shell variables references unless you have a good reason not to, and you’re sure you know what you’re doing.
  • G-Man Says 'Reinstate Monica'
    G-Man Says 'Reinstate Monica' over 9 years
    @jimmij: Why not say find -type f instead of making the shell do the test?
  • jimmij
    jimmij over 9 years
    @G-Man You are right, -type f would be simpler.