3

I need to make a list of all direct symbolic links in a directory, i.e. symbolic links that point to another file which is not a symbolic link.
I tried to do it this way:

for i in $(ls -1A); do

    first_type=$(ls -l $i | cut -b 1)

    if [ $first_type == 'l' ]
    then

        next=$(ls -l $i | awk '{print $NF}')
        next_type=$(ls -l $next | cut -b 1)

        if [ $next_type != 'l' ]
        then
            #Some code
        fi

    fi

done

But in this case, the script skips files whose names have spaces/tabs/newlines (including at the start and end of the file name). Is there any way to solve this?

I working on Solaris 10. There is no readlink or stat command. The find command does not have -printf.

iRomul
  • 43

2 Answers2

4

I can provide you with a perl snippet to do this for you:

#!/usr/bin/perl
#
foreach my $i (@ARGV) {
    # If it is a symlink then...
    -l $i and do {
        # First indirection; ensure that it exists and is not a link
        my $j = readlink($i);
        print "$i\n" if -e $j and ! -l $j
    }
}

If you save that as /usr/local/bin/if-link and make it executable (chmod a+x /usr/local/bin/if-link) you can use it like this

/usr/local/bin/if-link * .*

To incorporate it in another script, you can use it as a one-liner

perl -e 'foreach my $i (@ARGV) { -l $i && do { my $j = readlink($i); print "$i\n" if -e $j and ! -l $j } }' * .*
Chris Davies
  • 116,213
  • 16
  • 160
  • 287
0

In addition to solutions using Perl I decided to try to implement my own mini version readlink using readlink syscall. The source code of the utility using is very simple and looks like this:

ret_length = readlink( argv[1], buffer, buffer_size );

if( ret_length >= 0 ) {

    buffer[ ret_length ] = '\0';
    printf( "%s\n", buffer );
    return 0;

} else {    
    return errno;   
}

bash script (./xrl is name of utility; filenames that contains newline is unsupported):

USAGE="Usage: chl_xrl filename"
OLDIFS=$IFS
IFS=$'\n'

if [[ $# != 1 ]]
then
    echo $USAGE
    exit 1
fi

ls -1Au | while read -r pos; do

    if [[ $(./xrl "$pos") == $1 ]]
    then
        echo "$pos"
    fi

done    

IFS=$OLDIFS
exit 0

The one refinement - script takes a filename as parameter and looking for a direct link, but not for all files in a directory.

iRomul
  • 43