3

I am trying to create a script that foreach directoy in the folder folder, only the n most recent files are to be compressed.

However, I am having trouble with the multiple word files. I need a way to wrap them in quote marks so the tar command knows wich is each file.

Here is my script so far:

#!/bin/bash

if [ ! -d ~/backup ]; then
    mkdir ~/backup
fi

cd ~/folder
for i in *; do
    if [ -d "$i" ]; then
        original=`pwd`
        cd $i
        echo tar zcf ~/backup/"$i".tar.gz "`ls -t | head -10`"
        cd $original
    fi
done
echo "Backup copied in $HOME/backup/"
exit 0 
1
  • Do this error out? BTW, never parse the output of ls!
    – Braiam
    Apr 7, 2014 at 2:29

4 Answers 4

6

xargs to the rescue! One way is to use xargs to create argument list but put each file inside of quotes:

echo `ls -t1 | head -10 | xargs -I'{}' echo \"{}\"`

Other option it to use xargs to directly call tar in append mode (-r) and then compressing it at the end (you cannot create compressed archives in append mode):

ls -t | head -10 | xargs -I'{}' tar -rvf ~/backup/"$i".tar '{}'
gzip ~/backup/"$i".tar

The advantage of the 2nd approach is that you can change 10 to any other, even very high number and it will still work without getting too long argument list.

1

Perl to the rescue:

#!/usr/bin/perl
use warnings;
use strict;

my $backup = $ENV{HOME} . '/backup';
my $folder = $ENV{HOME} . '/folder';

-d $backup or mkdir $backup or die $!;
chdir $folder or die $!;
while (my $node = glob '*') {
    if (-d $node) {
        chdir $node;
        my @files = sort { -M $a <=> -M $b } glob '*';  # Sort files by age.
        @files = @files[0 .. 9] if @files > 10;         # Keep only the newest 10.
        system 'tar', 'zcf', "$backup/$node.tar.gz", @files;
        chdir '..';
    }
}
2
  • This was a bash question though. I need to do it in bash.
    – dabadaba
    Apr 6, 2014 at 13:02
  • @dabadaba: Always use the right tool for a job shrug
    – choroba
    Apr 7, 2014 at 8:50
1
n=3
shopt -s nullglob
for dir in */; do
    cd "$dir"
    files=(*)
    if (( ${#files[@]} > 0 )); then
        files=()
        while IFS= read -r filename; do
            files+=("$filename")
        done < <( stat -c "%Y %n" * | sort -n | cut -d " " -f 2- | head -n $n )
        tar cf ../"${dir%/}.tar" "${files[@]}"
    fi
    cd - &>/dev/null
done
1

You can try:

#!/bin/bash

if [ ! -d $HOME/backup ]; then
    mkdir $HOME/backup
fi

cd $HOME/folder
for i in *; do
    if [ -d "$i" ]; then
        tar -cf $HOME/backup/"$i".tar -T /dev/null #create an empty, uncompressed, archive
        cd "$i"
        ls -t | head -10 | while read file; do
            tar -rf $HOME/backup/"$i".tar "$file" #append $file to archive
        done
        gzip $HOME/backup/"$i".tar # compress the archive
        cd $OLDPWD
    fi
done
echo "Backup copied in $HOME/backup/"
exit 0 
1
  • @dabadaba OK, you should realize this from when I add my answer... I didn't used double double quotes in my answer ;) Now you can clean your comments, please? Apr 6, 2014 at 14:36

You must log in to answer this question.

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