1

Let's say I have the following directory hierarchy

|/home
|     |/john
|     |     |/app
|     |     |    |/folder1
|     |     |    |        |/data1.dat
|     |     |    |        |/...
|     |     |    |/folder2
|     |     |    |        |/...
|     |     |    |/cfg    
|     |     |    |        |/settings.cfg
|     |     |    |        |/...
|     |     |    |/start.sh
|     |/deer                             <-- I'm here
|     |     |/app

I need to symlink (for space reasons) all the files under /home/john/app excluded the files under /home/john/app/cfg (they are customized for each user) in /home/deer/app while preserving the subdirectories tree inside the app folder.

How can I achieve this? I tried already using a combination of rsync (to recreate the subfolders tree) and find (to list the files without the ones in cfg), however I am having difficulties telling ln to create the symlinks inside the correct subfolders.

rsync -a -f"+ */" -f"- *" /home/john/app/ app/
find /home/john/app/* -type f -exec ln -s '{}' app/ \; # I'm stuck here

Thanks in advance.

Robotex
  • 105
  • 1
  • 2
  • 10
  • There's no need to link *every* file under '/home/john/app'. Just link every dir but 'cfg', and every regular file under './app'. – agc Apr 03 '16 at 05:28
  • It's a simplification, in reality I have an another dir 'plugins' under a fourth dir named 'addons' which I wanted to exclude, so to do that I'd have to traverse the hierarchy level by level with maxdepth and that made it even more confusing to me. – Robotex Apr 03 '16 at 09:39
  • Ah, a 2nd exclusion, in a subdir yet... I read this after posting an answer that didn't account for that. Hmm... – agc Apr 03 '16 at 14:17
  • If 'app/addons/plugins' is out too, then also exclude the whole 'addons' directory, as per code in the answer section. Then process 'addons' seperately, using the same code, suitably modified. Perhaps a script that generalizes the process would be best. – agc Apr 03 '16 at 14:23

2 Answers2

0

I managed to achieve what I wanted in a 'hackish' way by changing the work directory and retrieving relative paths with find, here's what I did

# Some variables
basedir="/home/john"
currentdir=$(pwd)

# Duplicate directory tree
rsync -a -f"+ */" -f"- *" ${basedir}/app/ app/

# Create links
(cd ${basedir}; find * -type f -path "app/*" -not -path "*/cfg*" -exec ln -s ${basedir}/'{}' ${currentdir}/'{}' \;)

The parentheses are there to cancel the effect of cd

Still, I welcome any prettier solution.

Robotex
  • 105
  • 1
  • 2
  • 10
0

Before (an ad hoc copy of the spec in the OP):

% tree /home/
/home/
├── deer
│   └── app
└── john
    └── app
        ├── cfg
        │   └── settings.cfg
        ├── folder1
        │   └── data1.dat
        ├── folder2
        └── start.h

8 directories, 3 files

Code, with no rsync, featuring what man ln calls the "2nd form" of ln syntax 'ln TARGET' (create a link to TARGET in the current dir); (also ln *-sr for relative symlinks):

cd /home/deer/app/
find /home/john/app/ -maxdepth 1 -not -path "*/cfg" -not -path "*/app/" -exec ln -sr '{}' \;  ; 
cd - > /dev/null

...after:

% tree /home/
/home/
├── deer
│   └── app
│       ├── folder1 -> ../../john/app/folder1
│       ├── folder2 -> ../../john/app/folder2
│       └── start.h -> ../../john/app/start.h
└── john
    └── app
        ├── cfg
        │   └── settings.cfg
        ├── folder1
        │   └── data1.dat
        ├── folder2
        └── start.h

9 directories, 4 files
agc
  • 7,973
  • 2
  • 29
  • 50