2

I have a directory structure as below:

source-dir---
            |----- file-1
            |----- file-2
            |----- file-3
            |----- folder-1
                      |---- file-4
                      |---- file-5

I want to copy all the files from the source directory to destination directory and maintain the same folder structure but I want to avoid copying the file-5 from its sub-directory.

Expecting the destination directory to be as follow:

destination-dir---
                 |----- file-1
                 |----- file-2
                 |----- file-3
                 |----- folder-1
                           |---- file-4

Is it possible to achieve above behaviour using cp command itself? or rsync or any specific regex using find command?

αғsнιη
  • 40,939
  • 15
  • 71
  • 114
Ankit Raj
  • 173
  • 1
  • 6
  • Does the filename `file-5` only occur in `folder-1`, or can a file of the same name appear in other parts of the directory tree as well? – AdminBee May 20 '21 at 07:32
  • @AdminBee the file-5 only occur in folder-1 and is unique, I was trying this rsync command but it was not working. rsync -a --exclude={'file-5', '/source-dir/folder-1/*'} ~/source/ ~/destination/, Other way is if I execute single line bash : cp -r ~/source/* ~/destination/; rm ~/destination/folder-1/file-5, Do you have any better suggestion or solution? – Ankit Raj May 20 '21 at 07:47
  • 2
    since I saw you never have accepted any answer you received on your question (Stackexchange networks wide), please consider to a read this page [What does it mean when an answer is "accepted"?](https://unix.stackexchange.com/help/accepted-answer) about how to accept an answer and what accepting an answer means. – αғsнιη May 20 '21 at 17:17

3 Answers3

3

This should work, excluding only file-5 from copying in any level of sub-directories of the source directory but not if it exist in the top level:

cd /path/to/source
find . ! -path './*/file-5' -type d,f -exec sh -c '
    [ -d "$1" ] && echo mkdir -vp "/path/to/dest/$1" || echo cp -v "$1" "/path/to/dest/$1"
' sh_cp {} \;

if you only want to exclude that specifc file from a specifc subdirectory, strictly mention that instead, like ./folder-1/file-5 to exclude only this file and from that directory only.

remove echo in front of the mkdir and cp commands if you were happy with dry-run result.

αғsнιη
  • 40,939
  • 15
  • 71
  • 114
2

If I understand you correctly, you wanted to skip copying a specific file (file-5) from a specific directory (folder-1) then you can instruct rsync to exclude the said file as follows:

$ rsync -avz -f'- folder-1/file-5' ~/source/ ~/destination/
guest_7
  • 5,698
  • 1
  • 6
  • 13
1

This question make me thinks to bash globbing

This is a little script with explanation comment:

#!/bin/bash

# Check that the arguments are two.
# Source and destination
[ ${#@} -eq 2 ] || exit 1

# Remove, a possible, traling backslash
src="${1%/}"
dst="${2%/}"

# Enalble needed option for gloobin
shopt -q extglob || shopt -s extglob
shopt -q globstar || shopt -s globstar

# Set here the name to ignore
GLOBIGNORE="$src"/*/file-5

for e in "$src"/**; do
    # Skip the base directory
    [ "$e" != "$src/" ] || continue

    # If we process a directory then create it
    # in the destionation
    [ -d "$e" ] && echo mkdir "$dst/$e" && continue

    # Plain file, do then copy
    [ -f "$e" ] && echo cp "$e" "$dst/"
done

Rename the script, eg: sample.sh, then call as sample.sh src_path dst_path

Remove the echo when happy. Of course you can set the GLOBIGNORE to whatever you need to skip.

DanieleGrassini
  • 2,769
  • 5
  • 17