1

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

/var/www/bak/site1/www/file.tar.gz
/var/www/bak/site1/db/file.tar.gz
/var/www/bak/site2/www/file.tar.gz
/var/www/bak/site2/db/file.tar.gz

update

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'}
}

output="$(find_tarballs)"
set -- $output
shift
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"
    else
        echo "Filesize: $(filesize $tarball)"
    fi
    echo ''
done
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 '17 at 15:14
  • in some subdirs only some of the sub-subdirs is parsed.. – clarkk Apr 28 '17 at 15:15
  • sorry.. its because some of the files are tar.xz – clarkk Apr 28 '17 at 15:26
  • thats much better.. but how do I implement the tar -tvf file.tar.* part? – clarkk Apr 28 '17 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 '17 at 15:32
2

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 '17 at 8:59
  • @clarkk, see edit with alternative for GNU systems. – Stéphane Chazelas Apr 29 '17 at 10:40

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.