I created a short script to do this, with a nice output which should be easy check the results. It doesn't need to have the destination directory structure created. Use as follows:
$ ./recursive-symlink.sh --help
Usage:
./recursive-symlink.sh <source_path> <dest_path> <find_args...>
To show its usage, let's say I have the following files/dirs at the begining:
├── recursive-symlink.sh*
└── src/
├── dir1/
│ ├── file_A_misc.txt
│ └── file_B_sub.txt
├── dir3/
│ ├── file_A3.txt
│ ├── file_C.txt
│ └── subsub_dir/
│ ├── file_Asubsub.txt
│ └── file_D.txt
├── dir_A/
│ └── should_be_empty.dat
├── file_A.txt
└── file_B.txt
If I run:
$ find -name '*_A*'
./src/file_A.txt
./src/dir3/file_A3.txt
./src/dir3/subsub_dir/file_Asubsub.txt
./src/dir_A
./src/dir1/file_A_misc.txt
I can see which files would be linked. I then run the script like this:
$ ./recursive-symlink.sh src/ dest/ -name '*_A*'
src/file_A.txt
mkdir: created directory 'dest'
'dest/file_A.txt' -> '../src/file_A.txt'
src/dir3/file_A3.txt
mkdir: created directory 'dest/dir3'
'dest/dir3/file_A3.txt' -> '../../src/dir3/file_A3.txt'
src/dir3/subsub_dir/file_Asubsub.txt
mkdir: created directory 'dest/dir3/subsub_dir'
'dest/dir3/subsub_dir/file_Asubsub.txt' -> '../../../src/dir3/subsub_dir/file_Asubsub.txt'
src/dir_A
'dest/dir_A' -> '../src/dir_A'
src/dir1/file_A_misc.txt
mkdir: created directory 'dest/dir1'
'dest/dir1/file_A_misc.txt' -> '../../src/dir1/file_A_misc.txt'
My final state will be then:
├── recursive-symlink.sh*
├── src/
│ ├── dir1/
│ │ ├── file_A_misc.txt
│ │ └── file_B_sub.txt
│ ├── dir3/
│ │ ├── file_A3.txt
│ │ ├── file_C.txt
│ │ └── subsub_dir/
│ │ ├── file_Asubsub.txt
│ │ └── file_D.txt
│ ├── dir_A/
│ │ └── should_be_empty.dat
│ ├── file_A.txt
│ └── file_B.txt
└── dest/
├── dir1/
│ └── file_A_misc.txt -> ../../src/dir1/file_A_misc.txt
├── dir3/
│ ├── file_A3.txt -> ../../src/dir3/file_A3.txt
│ └── subsub_dir/
│ └── file_Asubsub.txt -> ../../../src/dir3/subsub_dir/file_Asubsub.txt
├── dir_A -> ../src/dir_A/
└── file_A.txt -> ../src/file_A.txt
You can see that dest
directory is created automatically, as well all recursive subdirectories, and on the dest
dir, only the files that matched the *_A*
pattern were linked.
Here the script source code:
#!/bin/bash
verbose='-v' # you may comment this line
if [ "$1" == '-h' ] || [ "$1" == '--help' ] || [ $# -lt 3 ]
then
echo "Usage:"
echo " $0 <source_path> <dest_path> <find_args...>"
exit
fi
src="${1%/}" ; shift
dest="${1%/}" ; shift
relflag='' ; [ "${src:0:1}" != '/' ] && relflag='-r'
find "$src" \( "$@" \) -print0 |
while IFS= read -r -d '' f
do
base_fname="${f#$src}"
[ "$verbose" ] && echo "${f}"
dest_ln="$dest/${base_fname#/}"
dest_dir="$(dirname "$dest_ln")"
mkdir -p $verbose "$dest_dir"
ln $relflag -s $verbose -t "$dest_dir" "$f"
[ "$verbose" ] && echo
done
Best Answer
If you used
find -name project/dir1/dir2
you will find a message like this:So, it offers certain alternatives for such task. Weird it doesn't mention the
-path
command to find:Please, notice the
*/
at the beginning. These tells find to print any path that ends with/project/dir1/dir2
and the name of the first directory has to beproject
otherwise it will findmyproject/dir1/dir2
and such.