Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems. It's 100% free, no registration required.

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

Is there a way to do this: "How can I copy a subset of files from a directory while preserving the folder structure?", but without using rsync?

Is it possible to be done using only cp, find and grep?

I have very limited bash shell (i.e. its a git shell under windows :( ), so rsync is not an option.

I know I can get cygwin, but I was wondering what I can do in this limited situation.

share|improve this question
Have you bash available? – enzotib Mar 5 '12 at 16:42
OT: robocopy can do that directly on windows (robocopy /S sourcedir targetdir *blah*) – Mat Mar 5 '12 at 16:54
or wget for windows – bsd Mar 5 '12 at 17:03
@enzotib: looks like its very limited bash, yes. – Sunny Mar 5 '12 at 17:28
up vote 7 down vote accepted

You can use tar or cpio or pax (if any of these is available) to copy certain files, creating target directories as necessary. With GNU tar, to copy all regular files called *.txt or README.* underneath the current directory to the same hierarchy under ../destination:

find . -type f \( -name '*.txt' -o -name 'README.*' \) |
tar -cf - -T - |
tar -xf - -C ../destination

With just find, cp, mkdir and the shell, you can loop over the desired files with find and launch a shell command to copy each of them. This is slow and cumbersome but very portable. The shell snippet receives the destination root directory as $0 and the path to the source file as $1; it creates the destination directory tree as necessary (note that directory permissions are not preserved by the code below) then copies the file. The snippet below works on any POSIX system and most BusyBox installations.

find . -type f \( -name '*.txt' -o -name 'README.*' \) -exec sh -c '
  mkdir -p "$0/${1%/*}";
  cp -p "$1" "$0/$1"
' ../destination {} \;

You can group the sh invocations; this is a little complicated but may be measurably faster.

find . -type f \( -name '*.txt' -o -name 'README.*' \) -exec sh -c '
  for x; do
    mkdir -p "$0/${x%/*}";
    cp -p "$x" "$0/$x";
' ../destination {} +

If you have bash ≥4 (I don't know whether Git Bash is recent enough), you don't need to call find, you can use the ** glob pattern to recurse into subdirectories.

shopt -s globstar extglob
for x in **/@(*.txt|README.*); do
  mkdir -p "../destination/${x%/*}"
  cp -p -- "$x" "../destination/$x"
share|improve this answer

You can try something like this:

ls | grep 2 | xargs -n1 -t -i cp -R {} ../testdirTwo/{}

I tried this on my Linux and it works. Note the -R parameter in cp, it's for recursive if you wish. Also note the -i parameter o xargs, it will insert it's output to where you put {}. -t is just for echoing the command to stderr.

My test directory structure looked like this:

$ find .
share|improve this answer

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.