LinuxQuestions.org
Help answer threads with 0 replies.
Home Forums Tutorials Articles Register
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices


Reply
  Search this Thread
Old 09-18-2012, 11:06 PM   #1
bloodclot
LQ Newbie
 
Registered: Apr 2012
Posts: 13

Rep: Reputation: Disabled
Shell Script help


Hello,

I have a basic question, looking for some help.

I am trying to find all the directories that have a soft link to them so I ran this -

time find . -maxdepth 1 -type l -print0 | xargs -0 ls -ld > /tmp/links.txt

If I have another file that has all the directories in the same dir I want to compare the files and remove the dirs that do not have any soft links..

Thanks in advance..
 
Old 09-19-2012, 12:20 AM   #2
konsolebox
Senior Member
 
Registered: Oct 2005
Distribution: Gentoo, Slackware, LFS
Posts: 2,248
Blog Entries: 8

Rep: Reputation: 235Reputation: 235Reputation: 235
Quote:
If I have another file that has all the directories in the same dir
Do you mean a list file, and that file's contents is similar to /tmp/links.txt?
Quote:
I want to compare the files and remove the dirs that do not have any soft links..
Do you mean with respect to the two files? I'm actually wondering if it's necessary to base it from them..
 
Old 09-19-2012, 08:36 AM   #3
bloodclot
LQ Newbie
 
Registered: Apr 2012
Posts: 13

Original Poster
Rep: Reputation: Disabled
Well I have list of all the dirs in that directory.

So for example -

[root@otis flexlm]# ls -l
total 24
lrwxrwxrwx 1 root root 7 Jan 7 2010 bin -> v11.4.1
drwxr-xr-x 10 root root 4096 Oct 7 2011 daemons
drwxr-xr-x 2 root root 4096 Jul 5 14:46 licenses
drwxr-xr-x 2 root root 4096 Aug 3 09:39 log
drwxr-xr-x 3 root root 4096 May 9 2011 tmp
drwxr-xr-x 2 root root 4096 May 2 2007 v10.8.0.1
drwxr-xr-x 5 root root 4096 Jan 7 2010 v11.4.1

So if this was the case I would want to delete all dirs but bin and v11.4.1.
 
Old 09-19-2012, 11:09 AM   #4
tc_
LQ Newbie
 
Registered: Sep 2010
Location: Germany
Distribution: Slackware
Posts: 28

Rep: Reputation: 30
Haha... I just spend quite a time on this... and I am so sure, that there is a better method than mine.

Anyway, here is the scarcely commented code:
Code:
#!/bin/bash

# build an array of all directories in ${alldirs}
# and an array of all symlinks and all their targets in ${keep}
#
# WARNING WARNING WARNING: double symlinks a->b->c will be missed!
for f in *; do
    if [ -d ${f} ]; then
        alldirs[${#alldirs[@]}]=${f}

        if [ -h ${f} ]; then
            keep[${#keep[@]}]=${f}
            target=$(readlink -f ${f})

            if [ $(dirname ${target}) !=  ${PWD} ]; then
                echo "WARNING: Target ${target} of symlink ${f} is outside of current directory"
            fi
            keep[${#keep[@]}]=$(basename ${target})
        fi
    fi
done

# sort both arrays
skeep=( $( printf '%s\n' "${keep[@]}" | sort ) )
salldirs=( $( printf '%s\n' "${alldirs[@]}" | sort ) )

non_slink=()

# consider both sorted arrays, throwing away entries occuring in both.
# to this end, we only need to compare the lowest/greatest elements, for 
# both arrays are sorted.

while [[  "${#skeep[@]}" != "0"  &&  "${#salldirs[@]}" != "0"  ]]; do

    while [[  "${#skeep[@]}" != "0"                                             \
            && "${#salldirs[@]}" != "0"                                         \
            && ! ${skeep[${#skeep[@]}-1]} < ${salldirs[${#salldirs[@]}-1]}  \
    ]]; do
        if [[ ${skeep[${#skeep[@]}-1]} == ${salldirs[${#salldirs[@]}-1]} ]]; then
            unset salldirs[${#salldirs[@]}-1]
        fi
        unset skeep[${#skeep[@]}-1]
    done

    while [[    ( "${#salldirs[@]}" != "0" )                                     \
            &&  ( ${skeep[ ${#skeep[@]}-1 ]} < ${salldirs[ ${#salldirs[@]}-1 ]} )\
    ]]; do
        non_slink[${#non_slink[@]}]=${salldirs[${#salldirs[@]}-1]}
        unset salldirs[${#salldirs[@]}-1]
    done
done

# append remaining sorted directories that did not occur in ${keep}
non_slink=( ${non_slink[@]} ${salldirs[@]} )

echo -e "\nAll directories that are neither source or target of symlink:"
echo ${non_slink[@]}
 
Old 09-19-2012, 01:53 PM   #5
bloodclot
LQ Newbie
 
Registered: Apr 2012
Posts: 13

Original Poster
Rep: Reputation: Disabled
Cheers TC!
 
Old 09-19-2012, 01:55 PM   #6
tc_
LQ Newbie
 
Registered: Sep 2010
Location: Germany
Distribution: Slackware
Posts: 28

Rep: Reputation: 30
That ugly solution above really bugged me. I now have a better solution, but decided to post it separately. The lesson I learned is, that even programs like 'comm', which take two files as parameters may be "fed" from stdin. Since comm does precisely the job you asked for -- namely computing the difference or intersection of two sequences of text -- it is then straightforward to write the script.

Enough talk, here is the code
Code:
#!/bin/bash

links=$( find . -maxdepth 1 -type l -printf '%f ' )
targets=
for l in ${links}; do
    targets="${targets} $(readlink ${l})"
done
non_slinks=$( comm -23 <( find . -maxdepth 1 -type d -printf '%f\n' | sort)  <( echo "${targets}" | sed -e 's/ /\n/g' | sort ) )

echo -e "\nAll directories that are neither source or target of symlink:"
echo ${non_slinks}
The command 'comm -23 FILE1 FILE2' reads two sorted files FILE1 and FILE2 and returns all the lines of FILE1 that do not occur in FILE2. In our case, FILE1 is a list of directories and FILE2 is a list of all the targets of symlinks. The targets of symlinks are build with 'readlink' and your original 'find -type l' solution. The 'sed s/ /\n/g' hack is "necessary" to separate the entries in the ${target} variable. Finally note that
Code:
find . -type d
does not return any symlinks by default. The manual page says that symlinks are a separate filetype.

Altogether, the only thing left from my first attempt, is using 'readlink' to determine the targets of symlinks. I hope this helps. I tested this script and it seemed to work. This solution is also way faster than my first attempt.

EDIT: There was a bug in my first second attempt. I really hope that this works now.

Last edited by tc_; 09-19-2012 at 03:17 PM. Reason: Bugfix and some explanation
 
  


Reply



Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
How to pass command line arguments from one shell script to another shell script VijayaRaghavanLakshman Linux - Newbie 5 01-20-2012 09:12 PM
Executing a Shell script with 654 permissions inside another shell script. changusee2k Linux - Newbie 2 06-07-2011 07:58 PM
pass variable from one shell script into another shell script xskycamefalling Programming 9 10-03-2009 01:45 AM
shell script problem, want to use shell script auto update IP~! singying304 Programming 4 11-29-2005 05:32 PM

LinuxQuestions.org > Forums > Non-*NIX Forums > Programming

All times are GMT -5. The time now is 10:05 AM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration