Listar links simbólicos diretos (links que não apontam para outro symlink)

3

Eu preciso fazer uma lista de todos os links simbólicos diretos em um diretório, isto é, links simbólicos que apontam para outro arquivo que não é um link simbólico.
Eu tentei fazer assim:

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

Mas, neste caso, o script ignora os arquivos cujos nomes têm espaços / guias / novas linhas (inclusive no início e no final do nome do arquivo). Existe alguma maneira de resolver isso?

Estou trabalhando no Solaris 10. Não há comando readlink ou stat . O comando find não tem -printf .

    
por iRomul 22.04.2015 / 21:55

2 respostas

4

Eu posso fornecer um snippet perl para você:

#!/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
    }
}

Se você salvar isso como /usr/local/bin/if-link e torná-lo executável ( chmod a+x /usr/local/bin/if-link ), você pode usá-lo assim

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

Para incorporá-lo em outro script, você pode usá-lo como one-liner

perl -e 'foreach my $i (@ARGV) { -l $i && do { my $j = readlink($i); print "$i\n" if -e $j and ! -l $j } }' * .*
    
por 22.04.2015 / 22:30
0

Além das soluções que usam o Perl, decidi tentar implementar o meu próprio readlink da versão mini usando syscall de readlink. O código-fonte do utilitário usado é muito simples e se parece com isso:

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

if( ret_length >= 0 ) {

    buffer[ ret_length ] = '
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
'; printf( "%s\n", buffer ); return 0; } else { return errno; }

script bash (./xrl é o nome do utilitário; nomes de arquivos que contêm nova linha não são suportados):

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

if( ret_length >= 0 ) {

    buffer[ ret_length ] = '
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
'; printf( "%s\n", buffer ); return 0; } else { return errno; }

O refinamento de um - script leva um nome de arquivo como parâmetro e procurando por um link direto, mas não para todos os arquivos em um diretório.

    
por 24.04.2015 / 14:58