Take the 2-minute tour ×
Ask Ubuntu is a question and answer site for Ubuntu users and developers. It's 100% free, no registration required.

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 
share|improve this question
    
Do this error out? BTW, never parse the output of ls! –  Braiam Apr 7 at 2:29

4 Answers 4

up vote 6 down vote accepted

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.

share|improve this answer

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 '..';
    }
}
share|improve this answer
    
This was a bash question though. I need to do it in bash. –  dabadaba Apr 6 at 13:02
    
@dabadaba: Always use the right tool for a job shrug –  choroba Apr 7 at 8:50
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
share|improve this answer

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 
share|improve this answer
    
@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? –  Radu Rădeanu Apr 6 at 14:36

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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