Como você pode ver o link físico real de ls?

80

eu corro

ln /a/A /b/B

Eu gostaria de ver na pasta a onde o arquivo A aponta para ls .

    
por Léo Léopold Hertz 준영 25.07.2009 / 11:41

10 respostas

147

Você pode encontrar o número de inode para seu arquivo com

ls -i

e

ls -l

mostra a contagem de referências (número de hardlinks para um determinado inode)

depois que você encontrou o número do inode, você pode procurar por todos os arquivos com o mesmo inode:

find . -inum NUM

mostrará nomes de arquivos para inode NUM no diretório atual (.)

    
por 25.07.2009 / 12:01
53

Não há realmente uma resposta bem definida para sua pergunta. Ao contrário dos links simbólicos, os hardlinks são indistinguíveis do "arquivo original".

As entradas de diretório consistem em um nome de arquivo e um ponteiro para um inode. O inode, por sua vez, contém os metadados do arquivo e (ponteiros para) o conteúdo real do arquivo). Criar um link físico cria outro nome de arquivo + referência para o mesmo inode. Essas referências são unidirecionais (em sistemas de arquivos típicos, pelo menos) - o inode mantém apenas uma contagem de referência. Não há maneira intrínseca de descobrir qual é o nome do arquivo "original".

A propósito, é por isso que a chamada do sistema para "excluir" um arquivo é chamada unlink . Apenas remove um hardlink. O inode e os dados anexados são excluídos somente se a contagem de referências do inode cair para 0.

A única maneira de encontrar as outras referências a um inode dado é pesquisar exaustivamente sobre o sistema de arquivos, verificando quais arquivos se referem ao inode em questão. Você pode usar 'test A -ef B' do shell para executar esta verificação.

    
por 25.07.2009 / 11:51
32

O UNIX possui links físicos e links simbólicos (feitos com "ln" e "ln -s" , respectivamente). Os links simbólicos são simplesmente um arquivo que contém o caminho real para outro arquivo e pode cruzar sistemas de arquivos.

Os links físicos existem desde os primeiros dias do UNIX (que eu me lembro de qualquer maneira, e isso está voltando por um bom tempo). São duas entradas de diretório que fazem referência aos mesmos dados subjacentes exatos . Os dados em um arquivo são especificados por seu inode . Cada arquivo em um sistema de arquivos aponta para um inode, mas não há exigência de que cada arquivo aponte para um inode exclusivo - é de onde vêm os links físicos.

Como os inodes são exclusivos apenas para um determinado sistema de arquivos, existe uma limitação de que os hard links devem estar no mesmo sistema de arquivos (ao contrário dos links simbólicos). Note que, ao contrário dos links simbólicos, não há arquivo privilegiado - eles são todos iguais. A área de dados só será liberada quando todos os arquivos que usam esse inode forem excluídos (e todos os processos também fecharem, mas isso é um problema diferente).

Você pode usar o comando "ls -i" para obter o inode de um arquivo específico. Você pode então usar o comando "find <filesystemroot> -inum <inode>" para encontrar todos os arquivos no sistema de arquivos com o inode fornecido.

Aqui está um script que faz exatamente isso. Você invoca com:

findhardlinks ~/jquery.js

e encontrará todos os arquivos nesse sistema de arquivos que são links físicos para esse arquivo:

pax@daemonspawn:~# ./findhardlinks /home/pax/jquery.js
Processing '/home/pax/jquery.js'
   '/home/pax/jquery.js' has inode 5211995 on mount point '/'
       /home/common/jquery-1.2.6.min.js
       /home/pax/jquery.js

Aqui está o script.

#!/bin/bash
if [[ $# -lt 1 ]] ; then
    echo "Usage: findhardlinks <fileOrDirToFindFor> ..."
    exit 1
fi

while [[ $# -ge 1 ]] ; do
    echo "Processing '$1'"
    if [[ ! -r "$1" ]] ; then
        echo "   '$1' is not accessible"
    else
        numlinks=$(ls -ld "$1" | awk '{print $2}')
        inode=$(ls -id "$1" | awk '{print $1}' | head -1l)
        device=$(df "$1" | tail -1l | awk '{print $6}')
        echo "   '$1' has inode ${inode} on mount point '${device}'"
        find ${device} -inum ${inode} 2>/dev/null | sed 's/^/        /'
    fi
    shift
done
    
por 25.07.2009 / 14:13
23
ls -l

A primeira coluna representará as permissões. A segunda coluna será o número de subitens (para diretórios) ou o número de caminhos para os mesmos dados (links físicos, incluindo o arquivo original) no arquivo. Por exemplo:

-rw-r--r--@    2    [username]    [group]    [timestamp]     HardLink
-rw-r--r--@    2    [username]    [group]    [timestamp]     Original
               ^ Number of hard links to the data
    
por 25.07.2009 / 12:01
9

Como sobre o seguinte mais simples? (Último pode substituir os scripts longos acima!)

Se você tiver um arquivo específico <THEFILENAME> e quiser saber todos os seus hardlinks espalhados pelo diretório <TARGETDIR> , (que pode até ser o sistema de arquivos inteiro indicado por / )

find <TARGETDIR> -type f -samefile  <THEFILENAME>

Estendendo a lógica, se você quiser saber todos os arquivos no <SOURCEDIR> com vários hard-links espalhados em <TARGETDIR> :

find <SOURCEDIR> -type f -links +1   \
  -printf "\n\n %n HardLinks of file : %H/%f  \n"   \
  -exec find <TARGETDIR> -type f -samefile {} \; 
    
por 15.08.2013 / 10:52
4

Existem muitas respostas com scripts para encontrar todos os hardlinks em um sistema de arquivos. A maioria faz coisas bobas como executar find para varrer todo o sistema de arquivos por -samefile para CADA arquivo com múltiplas conexões. Isso é loucura; tudo que você precisa é classificar o número de inode e imprimir duplicatas.

find directories.. -xdev ! -type d -links +1 -printf '%20D %20i %p\n' | sort -n | uniq -w 42 --all-repeated=separate (Obrigado ao @Tino por ajustar meu comando original para suportar um FS-id ( %D ), e para lidar com todos os tipos de arquivos não-diretórios, não apenas com arquivos regulares. links simbólicos, canais, etc.)

Usar ! -type d -links +1 significa que a entrada desse tipo é tão grande quanto a saída final do uniq. A menos que você o execute em um subdiretório que contenha apenas um conjunto de hardlinks. De qualquer forma, isso usará muito menos tempo de CPU para reencaminhar o sistema de arquivos do que qualquer outra solução publicada.

exemplo de saída:

...
            2429             76732484 /home/peter/weird-filenames/test/.hiddendir/foo bar
            2429             76732484 /home/peter/weird-filenames/test.orig/.hiddendir/foo bar

            2430             17961006 /usr/bin/pkg-config.real
            2430             17961006 /usr/bin/x86_64-pc-linux-gnu-pkg-config

            2430             36646920 /usr/lib/i386-linux-gnu/dri/i915_dri.so
            2430             36646920 /usr/lib/i386-linux-gnu/dri/i965_dri.so
            2430             36646920 /usr/lib/i386-linux-gnu/dri/nouveau_vieux_dri.so
            2430             36646920 /usr/lib/i386-linux-gnu/dri/r200_dri.so
            2430             36646920 /usr/lib/i386-linux-gnu/dri/radeon_dri.so
...

TODO ?: des-preenche a saída. uniq tem suporte de seleção de campo muito limitado, portanto, preenho a saída de localização e uso de largura fixa. 20chars é grande o suficiente para o máximo possível inode ou número do dispositivo (2 ^ 64-1 = 18446744073709551615). O XFS escolhe os números de inode com base no local em que eles estão alocados, não contiguamente a partir de 0, portanto, sistemas de arquivos XFS grandes podem ter números de inótipos de > 32 bits, mesmo que não tenham bilhões de arquivos. Outros sistemas de arquivos podem ter números de inodes de 20 dígitos, mesmo que não sejam gigantescos.

TODO: classifica grupos de duplicatas por caminho. Tendo eles classificados por ponto de montagem, o número de inode mistura as coisas juntas, se você tiver um par de subdiretórios diferentes que tenham muitos hardlinks. (isto é, grupos de grupos dup vão juntos, mas a saída os mistura).

Um sort -k 3 final classificaria as linhas separadamente, não grupos de linhas como um único registro. O pré-processamento com algo para transformar um par de novas linhas em um byte NUL e o uso do GNU sort --zero-terminated -k 3 pode ajudar. O tr só opera em caracteres únicos, não em padrões 2 > 1 ou 1 > 2. perl iria fazer isso (ou apenas analisar e ordenar dentro de perl ou awk). sed também pode funcionar.

    
por 21.04.2015 / 21:32
3

Isto é um pouco de um comentário à resposta e ao script do próprio Torocoro-Macho, mas obviamente não cabe na caixa de comentários.

Reescrevi seu script com maneiras mais simples de encontrar as informações e, portanto, muito menos invocações de processos.

#!/bin/sh
xPATH=$(readlink -f -- "${1}")
for xFILE in "${xPATH}"/*; do
    [ -d "${xFILE}" ] && continue
    [ ! -r "${xFILE}" ] && printf '"%s" is not readable.\n' "${xFILE}" 1>&2 && continue
    nLINKS=$(stat -c%h "${xFILE}")
    if [ ${nLINKS} -gt 1 ]; then
        iNODE=$(stat -c%i "${xFILE}")
        xDEVICE=$(stat -c%m "${xFILE}")
        printf '\nItem: %s[%d] = %s\n' "${xDEVICE}" "${iNODE}" "${xFILE}";
        find "${xDEVICE}" -inum ${iNODE} -not -path "${xFILE}" -printf '     -> %p\n' 2>/dev/null
    fi
done

Eu tentei mantê-lo o mais parecido possível com o seu para facilitar a comparação.

Comentários sobre este script e sobre o seu

  • Deve-se sempre evitar o $IFS magic se um glob é suficiente, já que é desnecessariamente complicado, e os nomes dos arquivos podem conter newlines (mas na prática, principalmente, o primeiro motivo).

  • Você deve evitar a análise manual do ls e da saída, tanto quanto possível, já que, mais cedo ou mais tarde, o morderá. Por exemplo: na sua primeira linha awk , você falha em todos os nomes de arquivos que contêm espaços.

  • printf geralmente salvará os problemas no final, pois é tão robusto com a sintaxe %s . Ele também lhe dá controle total sobre a saída e é consistente em todos os todos sistemas, ao contrário de echo .

  • stat pode poupar muita lógica neste caso.

  • GNU find é poderoso.

  • Suas invocações head e tail poderiam ter sido tratadas diretamente em awk com, por exemplo, o comando exit e / ou selecionando na variável NR . Isso economizaria invocações de processo, o que quase sempre melhoraria o desempenho de maneira severa em scripts que trabalham muito.

  • Seu egrep s poderia ser apenas grep .

por 13.06.2012 / 09:40
2

Com base no script findhardlinks (renomeado para hard-links ), isso é o que refatorei e fiz com que funcionasse.

Saída:

# ./hard-links /root

Item: /[10145] = /root/.profile
    -> /proc/907/sched
    -> /<some-where>/.profile

Item: /[10144] = /root/.tested
    -> /proc/907/limits
    -> /<some-where else>/.bashrc
    -> /root/.testlnk

Item: /[10144] = /root/.testlnk
    -> /proc/907/limits
    -> /<another-place else>/.bashrc
    -> /root/.tested

# cat ./hard-links
#!/bin/bash
oIFS="${IFS}"; IFS=$'\n';
xPATH="${1}";
xFILES="'ls -al ${xPATH}|egrep "^-"|awk '{print $9}''";
for xFILE in ${xFILES[@]}; do
  xITEM="${xPATH}/${xFILE}";
  if [[ ! -r "${xITEM}" ]] ; then
    echo "Path: '${xITEM}' is not accessible! ";
  else
    nLINKS=$(ls -ld "${xITEM}" | awk '{print $2}')
    if [ ${nLINKS} -gt 1 ]; then
      iNODE=$(ls -id "${xITEM}" | awk '{print $1}' | head -1l)
      xDEVICE=$(df "${xITEM}" | tail -1l | awk '{print $6}')
      echo -e "\nItem: ${xDEVICE}[$iNODE] = ${xITEM}";
      find ${xDEVICE} -inum ${iNODE} 2>/dev/null|egrep -v "${xITEM}"|sed 's/^/   -> /';
    fi
  fi
done
IFS="${oIFS}"; echo "";
    
por 16.11.2011 / 23:46
1

Uma solução de GUI aproxima-se da sua pergunta:

Você não pode listar os arquivos com link real de "ls" porque, como comentaram os comentadores anteriores, o arquivo "nomes" são meros aliases para os mesmos dados. No entanto, há realmente uma ferramenta GUI que fica realmente perto do que você quer, que é para exibir uma lista de caminhos de nomes de arquivos que apontam para os mesmos dados (como hardlinks) no Linux, é chamado FSLint. A opção que você deseja está em "Conflitos de nomes" - > desmarque "checkbox $ PATH" na pesquisa (XX) - > e selecione "Aliases" na caixa suspensa depois de "for ..." na direção do meio superior.

O FSLint está muito mal documentado, mas descobri que certificar a árvore de diretórios limitada em "Caminho de pesquisa" com a caixa de seleção marcada para "Recurse?" e as opções acima mencionadas, uma lista de dados vinculados com caminhos e nomes que "apontam" para os mesmos dados são produzidos após as procuras do programa.

    
por 20.01.2015 / 19:00
1

Você pode configurar ls para destacar os hardlinks usando um 'alias', mas como dito antes, não há como mostrar a 'fonte' do hardlink, e é por isso que eu adiciono .hardlink para ajudar com isso.

Adicioneoseguinteemalgumlugarnoseu.bashrc

aliasll='LC_COLLATE=CLS_COLORS="$LS_COLORS:mh=1;37" ls -lA --si --group-directories-first'
    
por 06.12.2017 / 18:34