Any way to find all symlinks pointing to /path/folder1/ ?

Brazen

Diamond Member
Jul 14, 2000
4,259
0
0
Title pretty much says it. I can do "find /path1/ -type l -exec rm '{}' \;" but that would delete all symlinks, which is bad. I need some way to narrow this down to check if the symlink points to /path/folder1/ and then delete if true.
 

Brazen

Diamond Member
Jul 14, 2000
4,259
0
0
Ah, ok I just found the readlink command. My guess is I will have to construct an if statement somewhat like this:

if ( find /path1/ -type l -exec readlink '{}' \; ) == /path/folder1/ then
rm something
end

but I'm sure this will not actually work with iterating through the find results (and I know this is not proper BASH syntax anyway). Just throwing out my thoughts...

I wonder if maybe instead I could put the if statement inside the find -exec like this:

find /path1/ -type l -exec
if readlink '{}' == /path/folder1/ then
rm '{}'
end
\;

Any thoughts, confirmations, or rebukes?
 

Nothinman

Elite Member
Sep 14, 2001
30,672
0
0
That looks about right, but I don't think -exec will take shell constructs so you could just create rmlink.sh and put the "should I delete this?" code in there.
 

Brazen

Diamond Member
Jul 14, 2000
4,259
0
0
Originally posted by: Nothinman
That looks about right, but I don't think -exec will take shell constructs so you could just create rmlink.sh and put the "should I delete this?" code in there.

Is there any other way I could group it all together? I would rather keep it all in one file if possible. Otherwise I suppose I would have to pass '{}' as a parameter to the rmlink.sh, right? So it would be ...-exec rmlink.sh '{}' \; That's a good idea. I need to set up a test environment so I can try this out.
 

Brazen

Diamond Member
Jul 14, 2000
4,259
0
0
Maybe this will work:

for file in $( find /path1/ -type l )
do
if [ `readlink $file` == "/path/folder1/" ] then
rm $file
fi
done

Does this look like proper syntax? Am I correct in the use of backticks around "readlink $file" and quotes around "/path/folder1/" ?
 

Brazen

Diamond Member
Jul 14, 2000
4,259
0
0
Ok, here is what I ended up with; I've tested it and it works :D :

for file in $( find /path1/ -type l ); do
if [ `readlink $file` = "/path/folder1/" ]; then
rm $file
fi
done

Thanks Nothinman for pointing out that -exec (probably) does not take shell constructs so I didn't go beating my head down that path :D

edit: wait this may not quite be final. I need to see if I can do a wildcard match to the path in the if statement, such as "/path/folder1/*" and I also need to, as a precaution, make sure the symlink begins with "@GMT-" which I suspect will work fine to use the -name param for 'find', such as:

for file in $( find /path1/ -type l -name \@GMT- ); do
if [ `readlink $file` = "/path/folder1/*" ]; then
rm $file
fi
done

I'll need to test this, but now it will probably have to wait as I need to get some sleep (I popped awake with this for loop idea and had to get it down :D )
 

esun

Platinum Member
Nov 12, 2001
2,214
0
0
I don't think you can use the wildcard there, but bash supports regular expressions so I'd use one of those.
 

Brazen

Diamond Member
Jul 14, 2000
4,259
0
0
Originally posted by: esun
I don't think you can use the wildcard there, but bash supports regular expressions so I'd use one of those.

I don't know regular expressions. How would I do that?
 

Nothinman

Elite Member
Sep 14, 2001
30,672
0
0
The main problem is that readlink just returns the string that the symlink points to not a real pathname. So if you have a link named blah pointing to /dev/null readlink will return "/dev/null" but if the link just points to null you'll just get "null" no matter where you run readlink from.
 

Brazen

Diamond Member
Jul 14, 2000
4,259
0
0
Originally posted by: Nothinman
The main problem is that readlink just returns the string that the symlink points to not a real pathname. So if you have a link named blah pointing to /dev/null readlink will return "/dev/null" but if the link just points to null you'll just get "null" no matter where you run readlink from.

For this situation at least, that is ok. I know all these symlinks will be pointing to full paths.

Nothinman, I don't know if you were involved in the discussion or if you remember, but back in December '06 I think I posted a discussion on creating a script to create snapshots and symlink to use with the shadow_vol module in Samba. The snapshot is always created in the same spot and then symlinks are created so that shadow_vol can find it. The solution I came up with was to store the name of the symlink in a file, and then read the file on subsequent snapshots to know the name of the symlink to delete. For some reason, however, occasionally a symlink gets left over so I have multiple symlinks (synlinks are named by date and time, which shadow_vol uses) that point to the same snapshot.

Another bonus is I think I can use this same new method to create my symlinks. Right now I have a long list in the script of symlinks that need to be created in each directory. I should be able to modify this for loop to create a symlink in the top level of every directory which will have the bonus of easily creating symlinks in people's home directories! (We don't use shadow_vol with home directories, which is where users' "My Documents" folders are redirected to because maintaining the list of directories for symlinks would be ungodly!)
 

Brazen

Diamond Member
Jul 14, 2000
4,259
0
0
This thread is old, but i finally got around to finishing my script, and I thought I would share it for anyone else working with shadow_vol or whatever else would need symlinks like this. This is not the entire script for my shadow volumes, but this is the symlink part. Note that this will also dynamically create symlinks in any new directories created, particularly home directories and also deletes symlinks without having to remember the "@GMT-blah" name of the symlink:

 

Brazen

Diamond Member
Jul 14, 2000
4,259
0
0
Wow, that formatting did not turn out well at all. This may be better:

#!/bin/bash
# Creating Shadow Copies

# The snapshot name used in the mount path
SNAP=Snap1

# removing symlinks
for link in $( find /export/share -maxdepth 2 -type l ); do
if [[ `readlink $link` =~ "^/export/snaps/${SNAP}.*" ]]; then
rm $link
fi
done

# remove My Documents links
for link in $( find /export/homes -maxdepth 3 -type l ); do
if [[ `readlink $link` =~ "^/export/snaps/${SNAP}.*" ]]; then
rm $link
fi
done
echo "symlinks deleted..."
# end of deleting links

#### This is where your code would go for removing the old snapshot and creating a new one
#### I use a proprietary app called admsnap to do this, so this part of my script would
#### not do most people any good unless they owned an EMC Clariion CX300.

SHADOWNAME=`date -u +%Y.%m.%d-%H.%M.%S`

echo "creating the plethora of symlinks..."
# "share" nested mappings
for directory in $( find /export/share -maxdepth 1 -type d ); do
TARGET=`echo $directory | sed "s/^\/export\/share/\/export\/snaps\/${SNAP}\/share/"`
ln -s $TARGET ${directory}/@GMT-$SHADOWNAME
done

# the redirected My Documents directories
for directory in $( find /export/homes -maxdepth 2 -type d ); do
TARGET=`echo $directory | sed "s/^\/export\/homes/\/export\/snaps\/${SNAP}\/homes/"`
ln -s $TARGET ${directory}/@GMT-$SHADOWNAME
done

echo "links created..."

echo "done."

That formatting doesn't look very good either, but it is the best I can do :(