How to make a recursive loop through a path and get the latest created tar.gz file in each directory?

I want to run tar -tvf file.tar.gz on the latest created file in each directory

All the tar.gz files are located in the second directory level.. So the maxdepth of the loop is 2

This script will only print each directory

cd $base_dir
find . -type d -printf '%f\n'

The base dir is /var/www/bak and all the tar.gz files are located like



find_tarballs (){
    cd $base_dir
    find . -name \*.tar.\* -execdir sh -c "echo -n \"\${PWD}/\"; ls -t *.tar.* | head -n 1" \; | sort -u -k1,1

filesize (){
    ls -lh $1 | awk -F " " {'print $5'}

set -- $output
for tarball; do
    echo "$tarball"
    if [ ${tarball##*.} = 'gz' ]; then
        list="$(tar -tzf $tarball)"
        echo "Filesize: $(filesize $tarball), Files: $(echo "$list" | wc -l)\n"
        echo 'Press ENTER to list files...'
        read key
        echo "$list"
        echo "Filesize: $(filesize $tarball)"
    echo ''

2 Answers 2


Assuming your paths don’t contain spaces or newlines:

find . -name \*.tar.\* -execdir sh -c "echo -n \"\${PWD} \"; ls -t *.tar.* | head -n 1" \; | sort -u -k1,1

will find all the tarballs, run the given shell snippet in each containing directory, and filter the result so that only one result is kept for each directory.

To view the tarballs’ contents, assuming their filenames also don’t contain spaces or newlines:

find . -name \*.tar.\* -execdir sh -c "echo -n \"\${PWD} \"; ls -t *.tar.* | head -n 1" \; | sort -u -k1,1 | tr ' ' / | xargs -n 1 tar tvf

will replace the space separating the path from the filename by “/”, and pass the result on to xargs which will run tar tvf on each file.

To prompt between each tarball, add -p to the xargs command:

find . -name \*.tar.\* -execdir sh -c "echo -n \"\${PWD} \"; ls -t *.tar.* | head -n 1" \; | sort -u -k1,1 | tr ' ' / | xargs -p -n 1 tar tvf
  • This script doesn't print all files..
    – clarkk
    Apr 28, 2017 at 15:14
  • in some subdirs only some of the sub-subdirs is parsed..
    – clarkk
    Apr 28, 2017 at 15:15
  • sorry.. its because some of the files are tar.xz
    – clarkk
    Apr 28, 2017 at 15:26
  • thats much better.. but how do I implement the tar -tvf file.tar.* part?
    – clarkk
    Apr 28, 2017 at 15:31
  • and is it possible to add a read after each tar -tvf with press enter to see next file contents ?
    – clarkk
    Apr 28, 2017 at 15:32

With zsh, in typical write-only fashion:

for dir (*/*(N/)) (){(($#)) && tar tvf $1} $dir/*.tar.gz(Nom[1])
  • for var (values) cmd: shorter form of for var in values; do cmd; done
  • (N/), (Nom[1]): glob qualifiers
    • N: expands to nothing if there's no match (nullglob)
    • /: directories only
    • om: order by modification time (newest first)
    • [1]: first match only
  • (){...} args: anonymous functions with its args.

With GNU tools (still making no assumption on what bytes file names may contain but traversing hidden directories and including hidden tar.gz files) and any Bourne-like shell, the equivalent could be:

LC_ALL=C find . -mindepth 3 -maxdepth 3 -name '*.tar.gz' -printf '%T@:%p\0' |
  sort -zn | LC_ALL=C awk -v RS='\0' -v ORS='\0' '
    {match($0, ":((.*)/.*)", parts); newest[parts[2]] = parts[1]}
    END {for (dir in newest) print newest[dir]}' |
    xargs -r0n1 tar tvf        
  • I only have native shell available
    – clarkk
    Apr 29, 2017 at 8:59
  • @clarkk, see edit with alternative for GNU systems. Apr 29, 2017 at 10:40

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .