List directories and count files inside

I'm trying to make a script that will list all directories under a selection as well as the number of files in each.
I cannot get it to work under a symbolic link.
The file structure is:

XXX_20131127_001
     dir01 (sym link)
            2404x912
                  file.0000.xxx to
                  file.0053.xxx
     dir02 (sym link)
            2404x912
                  file.0000.xxx to
                  file.0104.xxx
     dir03 (sym link)
            2404x912
                  file.0000.xxx to
                  file.0457.xxx
     dir03 (sym link)
            2404x912
                  

I was hoping for an output something like this:
dir01 54 files
dir02 105 files
dir03 458 files
dir04 0 files

On a different note, I also need a script that will display the first and last folders in the directory. Like this:

dir01
   2404x912
        file.0000.xxx
        file.0053.xxx

Any help would be great.
Thanks in advance.

Hi
Try a recursive combination between foreach and ls to list folders contents and count thier number:

foreach $dir in (ls -d /yourDir)
$nbr=$(ls -lt) 
if ($nbr=0)
{echo the dir is empty}
elif ( $(ls -d /yourDir/$in)>0
# a new foreach in the sub dir
 foreach()
end

For the second command try the trre command whitch is available in Unix and Unix-like systems:

Sorry I haven't unix to provide an accurate answer

Try this:

$ for dir in XXX_20131127_001/*
do
    echo $(basename $dir) $(find -L $dir -type f -print | wc -l) files
done
dir01 54 files
dir02 105 files
dir03 458 files
dir04 0 files

For you treeview:

$ find . -depth -type d -print | while read path
do
    path=${path#./}
    if [ ${#path} -ge ${prev:-0} ]
    then
        prev=${#path}
        indent=""
        IFS='/'
        set -- $path
        IFS=$' \t\n'
        while [ $# -gt 0 ]
        do
           echo "$indent$1"
           indent="   $indent"
           shift
        done
        echo "$indent$(ls $path | head -1)"
        echo "$indent$(ls $path | tail -1)"
    fi
done
dir01
   2404x912
      file.0000.xxx
      file.0053.xxx
dir02
   2404x912
      file.0000.xxx
      file.0104.xxx
dir03
   2404x912
      file.0000.xxx
      file.0457.xxx

That almost worked. I altered it slightly and now it works great.


find . -depth -type l -print | while read path
do
    path=${path#./}
    if [ ${#path} -ge ${prev:-0} ]
    then
        prev=${#path}
        indent=""
        IFS='/'
        set -- $path
        IFS=$' \t\n'
        while [ $# -gt 0 ]
        do
           echo "$indent$1"
           indent="   $indent"
           shift
        done
        echo "$indent$(ls $path | head -1)"
        echo "$indent$(ls $path | tail -1)"
    fi
done

Thank you very much!

---------- Post updated at 01:35 PM ---------- Previous update was at 01:16 PM ----------

I spoke too soon. That script works if there are no sub directories.
Without sub directories result:

DPX
   pe0880_v400002
      pe0880_v400002.1000.dpx
      pe0880_v400002.1041.dpx
DPX
   pe0880_v400003
      pe0880_v400003.1000.dpx
      pe0880_v400003.1041.dpx
DPX
   pg1100_v400019
      pg1100_v400019.1000.dpx
      pg1100_v400019.1120.dpx
QT
   pe0880_v400002.mov
      QT/pe0880_v400002.mov
      QT/pe0880_v400002.mov
QT
   pe0880_v400003.mov
      QT/pe0880_v400003.mov
      QT/pe0880_v400003.mov
QT
   pg1100_v400019.mov
      QT/pg1100_v400019.mov
      QT/pg1100_v400019.mov

With subdirectories the result:

DPX
   pe0880_v400002
      2404x912
      2404x912
DPX
   pe0880_v400003
      2404x912
      2404x912
DPX
   pg1100_v400019
      2404x912
      2404x912
QT
   pe0880_v400002.mov
      QT/pe0880_v400002.mov
      QT/pe0880_v400002.mov
QT
   pe0880_v400003.mov
      QT/pe0880_v400003.mov
      QT/pe0880_v400003.mov
QT
   pg1100_v400019.mov
      QT/pg1100_v400019.mov
      QT/pg1100_v400019.mov

Ideally, only the .dpx files would show first and last. Any other file type would simply be listed.
Like this:

DPX
   pe0880_v400002
      2404x912
         pe0880_v400002.1000.dpx
         pe0880_v400002.1041.dpx

   pe0880_v400003
      2404x912
         pe0880_v400003.1000.dpx
         pe0880_v400003.1041.dpx

   pg1100_v400019
      2404x912
         pg1100_v400019.1000.dpx
         pg1100_v400019.1120.dpx
QT
   pe0880_v400002.mov
   pe0880_v400003.mov  
   pg1100_v400019.mov

    

This should work better but requires bash shell, I can do a ksh version if you require.

#!/bin/bash
find -L . -depth \( -type l -o -type d \) -print | while read path
do
    path=${path#./}
    IFS='/' PTH=( $path )
    if [[ ${#PTH[@]} -ge ${#prev[@]} ]]
    then
        indent=""
        diff=0
        for((i=0;i<${#PTH[@]};i++)) {
           if [[ diff -eq 1 || "${PTH}" != "${prev}" ]]
           then
              echo "$indent${PTH}"
              diff=1
           fi
           indent="   $indent"
        }
        if ls "$path" | grep -q "\.dpx$"
        then
            echo "$indent$(ls "$path" | grep "\.dpx$" | head -1)"
            echo "$indent$(ls "$path" | grep "\.dpx$" | tail -1)"
        else
            ls "$path" | sed "s/^/$indent/"
        fi
        IFS='/' prev=( $path )
    fi
done

That script works great! Thanks.

I can usually understand what a script is doing once I see it but this one baffles me. Great work!

I was looking to see if I could add code that would list the quicktime files as well but I was lost in there. Better to leave it working I figure.

This will save me a lot of copy, paste, delete, tab, tab, select, tab, tab ...

Here is a version where you can specify a list of extensions you want to summarise, but it might play up a bit if you had a directory with mixed file types (eg qt and dpx files), just change EXTS to pipe list of values you would summarise:

EXTS="qt|dpx"
find -L . -depth \( -type l -o -type d \) -print | while read path
do
    path=${path#./}
    IFS='/' PTH=( $path )
    if [[ ${#PTH[@]} -ge ${#prev[@]} ]]
    then
        indent=""
        diff=0
        for((i=0;i<${#PTH[@]};i++)) {
           if [[ diff -eq 1 || "${PTH}" != "${prev}" ]]
           then
              echo "$indent${PTH}"
              diff=1
           fi
           indent="   $indent"
        }
        if ls "$path" | grep -Eq "\.($EXTS)$"
        then
            echo "$indent$(ls "$path" | grep -E "\.($EXTS)$" | head -1)"
            echo "$indent$(ls "$path" | grep -E "\.($EXTS)$" | tail -1)"
        else
            ls "$path" | sed "s/^/$indent/"
        fi
        IFS='/' prev=( $path )
    fi
done

I was thinking of putting something like this before the script:

find . -name "NRV*" -type d -maxdepth 1 -mtime -1 -exec "cd {}" \;

For some reason I can't get this to work right.
It echos correctly but won't perform the cd.

Every process in unix has it's own distinct working directory, the cd you are using in the above code will not change the working directory of the shell that ran the find command as the exec feature of find will run the cd command in a new sub shell.

You could use -print to output the sub-directory required and then use a cd command from within the shell it's self, something like this:

SUBDIR=$(find . -name "NRV*" -type d -maxdepth 1 -mtime -1 -print | head -1)
[ -n "$SUBDIR" ] && cd "$SUBDIR"

the [-n "$SUBDIR"] part is to test to ensure a directory was found before calling cd, and the head -1 is to select the first directory found when multiple match your find.

This doesn't work.
Oh, I see the problem. What I'm looking for is the newest directory, but I used -mtime 1 ... since it's Monday, the newest file is older than that.
Yep, using mtime -2 it works today, but it won't work tomorrow.

I hadn't thought about files older than a day. Is there a better way to specify the newest file?

OK, so you want to find the most recent modified directory with name "NRV*" under the current directory correct?

How about:

SUBDIR=$(ls -td NRV* | head -1)
[ -n "$SUBDIR" ] && cd "$SUBDIR"

If your looking for a directory at any depth you may need to do:

SUBDIR=$(find -L . -type d -name "NRV*" -printf '%T@ %p\n' | sort -nr | head -1 | cut -f2- -d" ")
[ -n "$SUBDIR" ] && cd "$SUBDIR"