0

I'm traversing a directory, looking for subdirectories, finding certain files, and copying them someplace else... I'm doing this:

for i in `ls ./*/filename`; do cp $i ../test2; done

This takes all those filenames and moves them into the test2 directory... thing is I also need the source dirname.... i think this can be done with awk but I'm clueless and struggling...

for i in `ls ./dirname/filename`; do cp ../test2/dirname/; done

I can't copy the entire dirname because I don't need all the files in there...

3

To copy the entire directory path for a particular file or directory to another directory, you have at least two options:

With cp from GNU coreutils, use --parents:

cp --parents ./*/sourcefile /some/path/destdir

With rsync, use -R or --relative:

rsync -R ./*/sourcefile /some/path/destdir

This will place each source file beneath it's source path under the destination directory, so that e.g. ./a/sourcefile is copied to /some/path/destdir/a/sourcefile in the command shown here.

Note that there is no need to loop over any files when doing this.

On a system without GNU cp and rsync, you could possibly do a loop, but you would not want to loop over the output of ls. Instead

for pathname in ./*/sourcefile; do
    destdir="/some/path/destdir/$(dirname "$pathname")"
    mkdir -p "$destdir" && cp "$pathname" "$destdir"
done

This would loop over all the files you'd like to copy, and for each file, it would make sure that the corresponding destination directory was present and then copy the file there.

Example:

$ tree
.
|-- dest
`-- src
    |-- a
    |   |-- file
    |   `-- something-else
    |-- b
    |   |-- file
    |   `-- something-else
    |-- c
    |   |-- file
    |   `-- something-else
    |-- d
    |   |-- file
    |   `-- something-else
    `-- e
        |-- file
        `-- something-else

7 directories, 10 files

Either of the above two commands (or the loop) entered here, with the source being ./src/*/file and the target being ./dest.

$ tree
.
|-- dest
|   `-- src
|       |-- a
|       |   `-- file
|       |-- b
|       |   `-- file
|       |-- c
|       |   `-- file
|       |-- d
|       |   `-- file
|       `-- e
|           `-- file
`-- src
    |-- a
    |   |-- file
    |   `-- something-else
    |-- b
    |   |-- file
    |   `-- something-else
    |-- c
    |   |-- file
    |   `-- something-else
    |-- d
    |   |-- file
    |   `-- something-else
    `-- e
        |-- file
        `-- something-else

13 directories, 15 files
-1

Try doing it with rsync -R (--relative) flag:

$ for i in ls ./*/filename; do rsync -avR $i ../test2; done

The -R flag syncs the full path given on the command line.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.