Zsh Mailing List Archive
Messages sorted by: Reverse Date, Date, Thread, Author

Re: Set difference between sets of files

On May 5,  5:57pm, Peter Stephenson wrote:
} > For instance, say I have two directories - master/ and backup/ -
} > containing (mostly) identical files. I would like to remove from
} > backup/ all files which have been removed from master/. I would like
} > to achieve this by doing something like this:
} >
} >     cd master/
} >     MASTER_FILES=(**/*(.))
} >     cd ../backup
} >     BACKUP_FILES=(**/*(.))
} >     TO_REMOVE=<set difference between BACKUP_FILES and MASTER_FILES>
} >     rm -f $TO_REMOVE

I'd typically do this like so:

rm $(for f in backup/**/*(.); [[ -e ${f:s@backup/@master/} ]] || print $f)

Of course that needs a bit of cleanup if any of the file names might have
spaces in them.

Another way is this:

    cd backup
    rm -f **/*(.e:'[[ ! -f ../master/$REPLY ]]':)

Neither of these uses set-differencing on arrays; sometimes you have to
think about alternate approaches to the original problem.

} It might be useful to have a special expression for excluding anything
} that matches an element of a given array, but there isn't one.

Here's another way:

typeset -A differ
eval differ\[${(q)^MASTER_FILES}\]=a
eval differ\[${(q)^BACKUP_FILES}\]=b
print -l -- ${(k)differ[(R)a]}

I tried using

eval noglob unset differ\[${(q)^BACKUP_FILES}\]

but that failed on names containing spaces, for some reason.

Messages sorted by: Reverse Date, Date, Thread, Author