#!/bin/sh usage () { cat <&2 ${0##*/} FOLDERS DEST Merge FOLDERS content into DEST. Existing files and folders will remain. It does not overwrite by default. Empty folders are ignored. The resulting hierarchy is: DEST/FOLDER1/ DEST/FOLDER2/ ... Options: -f: Overwrite destination. -r: Remove empty folders. WARNING: Do not use over filenames with newlines. EOF } OPT_OVERWRITE=false OPT_DELEMPTY=false while getopts ":fhr" opt; do case $opt in h) usage exit 1 ;; f) OPT_OVERWRITE=true ;; r) OPT_DELEMPTY=true ;; \?) usage exit 1 ;; esac done shift $((OPTIND - 1)) if [ $# -eq 0 ]; then usage exit 1 fi ## The counter is used to process all arguments but the last one. We can get the ## last argument with an 'eval'. (Safe here.) DEST="$(eval "echo \$$#")" count=0 for i ; do count=$((count+1)) [ $count -eq $# ] && break while IFS= read -r FILE; do DESTFILE="$DEST/$FILE" if [ ! -e "$DESTFILE" ] || $OPT_OVERWRITE; then mkdir -p "$(dirname "$DESTFILE")" mv -v "$i/../$FILE" "$DESTFILE" if $OPT_DELEMPTY; then PARENT="$FOLDER/../$FILE" PARENT="${PARENT%/*}" rmdir "$PARENT" 2>/dev/null fi fi ## We switch to $i so that 'find' strips the parent dirs from the path. done <