views:

929

answers:

3

Ok, this is my third try posting this, maybe I'm asking the wrong question!!

It's been a few years since I've done any shell programming so I'm a bit rusty...

I'm trying to create a simple shell script that finds all subdirectories under a certain named subdirectory in a tree and creates symbolic links to those directories (sounds more confusing than it is). I'm using cygwin on Windows XP.

This find/grep command finds the directories in the filesystem like I want it to:

find -mindepth 3 -maxdepth 3 -type d | grep "New Parts"

Now for the hard part... I just want to take that list, pipe it into ln and create some symlinks. The list of directories has some whitespace, so I was trying to use xargs to clean things up a bit:

find -mindepth 3 -maxdepth 3 -type d | grep "New Parts" | xargs -0 ln -s -t /cygdrive/c/Views

Unfortunately, ln spits out a long list of all the directories concatenated together (seperated by \n) and spits out a "File name too long" error.

Ideas??

+3  A: 

I think you can do this all within your find command. OTTOMH:

find -mindepth 3 -maxdepth 3 -type d -name "*New Parts*" -exec ln -s -t /cygdrive/c/Views {} \;

Hope I remembered that syntax right.

NWCoder
+1 for the -exec flag. People seem to forget this one a lot. You might want to enclose the {} in quotes though so it handles names with spaces in them ok.
Jeremy Wall
A: 

your command

find -mindepth 3 -maxdepth 3 -type d | grep "New Parts" | xargs -0 ln -s -t /cygdrive/c/Views

have argument "-0" to xargs but you did not tell find to "-print0" (if you did grep could not work in the pipe inbetween). What you want is the following I guess:

find -mindepth 3 -maxdepth 3 -type d | grep "New Parts" | tr '\012' '\000' | xargs -0 ln -s -t /cygdrive/c/Views

The tr command will convert newlines to ascii null.

hlovdal
Use `-name` instead of `grep` as in NWCoder's answer and you can use `-print0`.
Dennis Williamson
A: 

Use a for loop.

for name in $(find $from_dir -mindepth 3 -maxdepth 3 -type d); do
  ln -s $name $to_dir
done

Xargs has issues where the input from the pipe goes at the end of the command. What you want is multiple commands, not just 1 command.

My experience with doing things within the find command can sometimes be slow, although it does get the job done.

KFro
Your command will fail if one of the directories found contains spaces. You must add quotes, i.e. <<ln -s "$name" $todir>>. That is one of the great benefits of using "xargs -0" that you avoid all such issues.
hlovdal
Ah yes, of course. Pesky little escaping issues.
KFro