Hi everyone,

I'm trying to write a script that will list all files and their details within a directory - so for example, if I have the structure

/home/
/home/folder1/
/home/folder2/
/home/folder3/

It will print something like
+----------------------------
| /home/folder1/
+----------------------------
| *files here* | *size*
+----------------------------
| /home/folder2
+----------------------------
| *files here* | *size*


Although I seem to be having a bit of trouble so far - it will list all the files in one go, which is not what I want, they need to be separated by directory!

Does anyone know anyw way of doing this? I can post some code if anyone wants too take a look at it, and many thanks in advance :)

#!/bin/bash

OUTPUT=""
TAQ_FILES=""
DQR_FILES=""
TAQ_MD5=""
DQR_MD5=""

CURRENT_DIR=`pwd`

for dir in $(find $CURRENT_DIR  -type d);
do
    cd $dir
    echo "Currently Processing Files in $dir"
    OUTPUT=$OUTPUT"+-----------------------------------------------------------------------------------------------------+\n"
    OUTPUT=$OUTPUT"| TAQ Report for $dir\n"
    OUTPUT=$OUTPUT"+-----------------------------------------------------------------------------------------------------+\n"
    OUTPUT=$OUTPUT"| TAQ Files : `ls -l *.gz | wc -l` Total (`ls -l TAQ*.md5 | wc -l` md5 check sums); DQR Files : `ls -l *.txt | wc -l` Total (`ls -l DATA*.md5 | wc -l` md5 check sums) |\n"
    OUTPUT=$OUTPUT"+-----------------------------------------------------------------------------------------------------+\n"
    OUTPUT=$OUTPUT"| TAQ Files in directory\t\t\t\t\t| Size \t\t| MD5 Sum?\t\t|\n" 
    OUTPUT=$OUTPUT"+-----------------------------------------------------------------------------------------------------+\n"
    
    for file in $dir $(find -type f -iname "TAQ*.gz");
    do
        if [ $dir == $CURRENT_DIR ];
        then
        #    echo "home"
        #else
            TAQ_FILES=$TAQ_FILES"| `basename $file .csv.gz`\t\t\t\t| `ls -lh $file | awk '{print $5}'`\t\t|\n"
            if [ -e `basename $file .csv.gz`.md5  ];
            then
                echo `basename $file .csv.gz`.md5
                echo "md5 exists for $file"
            fi
        fi
    done
    
    OUTPUT=$OUTPUT$TAQ_FILES
    OUTPUT=$OUTPUT"+-----------------------------------------------------------------------------------------------------+\n"
    
    for file in $dir $(find -type f -iname "DATA*.txt");
    do
        if [ $dir == $CURRENT_DIR ];
        then
        #    echo "home"
        #else
            DQR_FILES=$DQR_FILES"| `basename $file .txt`\t\t\t\t| `ls -lh $file | awk '{print $5}'`\t\t|\n"
            # if [];
            # then

            # fi
        fi
    done
    
    OUTPUT=$OUTPUT$DQR_FILES
    OUTPUT=$OUTPUT"+-----------------------------------------------------------------------------------------------------+\n"
    
    DQR_FILES="" 
    TAQ_FILES=""
    
    echo -e $OUTPUT >> test.txt
done

Dani AI

Generated

tried to build a single giant OUTPUT string and then append it at the end; that pattern makes debugging hard and can produce the “all files in one go” effect you described. ’s ls -laR and ’s find -ls are quick, but they don’t produce the neat per-directory header blocks you want.

The main problems in the posted script are: the inner loop mixes $dir with a global find (so results aren’t limited to the current directory), the if [ $dir == $CURRENT_DIR ] check prevents processing subdirs, and unquoted variables plus parsing ls output makes the script fragile for names with spaces. Streaming output as you go (rather than building a huge variable) and using NUL-separated lists avoids those pitfalls.

A concise, robust pattern (works on GNU/Bash) that prints a header per directory, lists matching files in that directory with size and whether a corresponding .md5 file exists:

#!/usr/bin/env bash
base="${1:-.}"

find "$base" -type d -print0 | while IFS= read -r -d '' dir; do
  printf '+%0.s-' {1..90}; printf '\n| %s\n' "$dir"; printf '+%0.s-' {1..90}; printf '\n| %-60s | %-10s | %-6s |\n' "File" "Size" "MD5?"; printf '+%0.s-' {1..90}; printf '\n'
  find "$dir" -maxdepth 1 -type f \( -iname 'TAQ*.gz' -o -iname 'DATA*.txt' \) -print0 |
  while IFS= read -r -d '' file; do
    name=$(basename "$file")
    if stat --version >/dev/null 2>&1; then size=$(stat -c%s "$file"); else size=$(stat -f%z "$file"); fi
    md5_present=no
    [[ -e "${file}.md5" ]] && md5_present=yes
    printf '| %-60s | %10s | %-6s |\n' "$name" "$size" "$md5_present"
  done
  printf '+%0.s-' {1..90}; printf '\n\n'
done

Notes: the script uses NUL separators to handle spaces/newlines in names and checks for both GNU and BSD stat for portability. If you need actual MD5 verification instead of just presence, run md5sum -c on matching .md5 files but beware of the extra CPU cost on large archives.

Recommended Answers

All 2 Replies

How about:

#!/bin/bash
if [ $# -eq 0 ]; then
echo "You must supply a base directory to seach."
echo "usage: myscript <dir>"
exit 0
fi
ls -laR $1

or simply
ls -laR /home

I kind of like find for this because if "all" isn't exactly right, it is easy to tune.

find $basedir -print

or if you want a lot of detail:

find $basedir -ls
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.