#!/bin/bash usage() { echo "USAGE: $0 [--clobber] [--verbose] [--] dir zfs-dir zfsdataset@old-snap [[zfsdataset]@new-snap]" } verbose= debug() { if [ -n "$verbose" ] then echo "$@" fi } clobber=--no-clobber while [ "${1:0:1}" == "-" ] do case $1 in --) break ;; --verbose) verbose=true ;; --clobber) clobber=--force ;; --no-clobber) clobber=--no-clobber ;; *) >&2 echo "Unrecognized option: $1" usage exit 1 esac shift done if (( $# < 3 )) then usage exit 0 fi root="$1" prefix="$2" old_snap="$3" new_snap="$4" if [[ "${root:0-1}" != "/" ]] then root="$root/" fi if [[ "${prefix:0-1}" != "/" ]] then prefix="$prefix/" fi echo "Target directory: $root" echo "Source filesystem: $prefix" echo "Old snapshot: $old_snap" echo "New snapshot: $new_snap" debug zfs diff -H "$old_snap" "$new_snap" zfs diff -H "$old_snap" "$new_snap" | grep '^R' | grep -F -- "$prefix" | while read -r diffline do get_path() { path="$(echo -e "$(echo "$diffline" | cut -d$'\t' "-f$1")")" echo "${path/#$prefix/$root}" } from="$(get_path 2)" to="$(get_path 3)" debug "From: $from" debug "To: $to" debug mv '"'"$from"'"' '"'"$to"'"' mkdir -vp -- "$(dirname "$to")" if [ -e "$to" ] && [ "$clobber" != "--force" ] then echo "File exists, not clobbering: $to" fi mv -v "$clobber" -- "$from" "$to" || echo "Unable to move $from" done