Ask Ubuntu is a question and answer site for Ubuntu users and developers. Join them; it only takes a minute:

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

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:


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

cd ~/folder
for i in *; do
    if [ -d "$i" ]; then
        cd $i
        echo tar zcf ~/backup/"$i".tar.gz "`ls -t | head -10`"
        cd $original
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 '14 at 2:29
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:

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 '14 at 13:02
@dabadaba: Always use the right tool for a job shrug – choroba Apr 7 '14 at 8:50
shopt -s nullglob
for dir in */; do
    cd "$dir"
    if (( ${#files[@]} > 0 )); then
        while IFS= read -r filename; do
        done < <( stat -c "%Y %n" * | sort -n | cut -d " " -f 2- | head -n $n )
        tar cf ../"${dir%/}.tar" "${files[@]}"
    cd - &>/dev/null
share|improve this answer

You can try:


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

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
        gzip $HOME/backup/"$i".tar # compress the archive
        cd $OLDPWD
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 '14 at 14:36

Your Answer


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.