eu corro
ln /a/A /b/B
Gostaria de ver na pasta aonde o arquivo A aponta para ls.
eu corro
ln /a/A /b/B
Gostaria de ver na pasta aonde o arquivo A aponta para ls.
Respostas:
Você pode encontrar o número do inode para seu arquivo com
ls -i
e
ls -l
mostra a contagem de referências (número de hardlinks para um inode específico)
depois de encontrar o número do inode, você pode procurar todos os arquivos com o mesmo inode:
find . -inum NUM
mostrará os nomes dos arquivos para o inode NUM no diretório atual (.)
Não há realmente uma resposta bem definida para sua pergunta. Ao contrário dos links simbólicos, os links físicos são indistinguíveis do "arquivo original".
As entradas do 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 (indicadores 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 (pelo menos em sistemas de arquivos típicos) - o inode mantém apenas uma contagem de referência. Não há uma 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 serão excluídos apenas se a contagem de referência do inode cair para 0.
A única maneira de encontrar as outras referências a um determinado inode é pesquisar exaustivamente no sistema de arquivos, verificando quais arquivos se referem ao inode em questão. Você pode usar 'test A -ef B' no shell para executar esta verificação.
O UNIX possui links físicos e simbólicos (criados com "ln"e "ln -s"respectivamente). Links simbólicos são simplesmente um arquivo que contém o caminho real para outro arquivo e pode atravessar sistemas de arquivos.
Os hard links existem desde os primeiros dias do UNIX (que eu me lembro de qualquer maneira, e isso já faz um bom tempo). São duas entradas de diretório que referenciam exatamente os mesmos dados subjacentes. Os dados em um arquivo são especificados por seus inode. Cada arquivo em um sistema de arquivos aponta para um inode, mas não é necessário que cada arquivo aponte para um inode exclusivo - é daí que os links físicos vêm.
Como os inodes são exclusivos apenas para um determinado sistema de arquivos, há uma limitação de que os links físicos devem estar no mesmo sistema de arquivos (diferente dos links simbólicos). Observe que, diferentemente dos links simbólicos, não há arquivo privilegiado - todos são iguais. A área de dados será liberada somente quando todos os arquivos que usam esse inode forem excluídos (e todos os processos também serão fechados, mas esse é um problema diferente).
Você pode usar o "ls -i"comando para obter o inode de um arquivo específico. Você pode usar o "find <filesystemroot> -inum <inode>"comando para encontrar todos os arquivos no sistema de arquivos com o inode fornecido.
Aqui está um script que faz exatamente isso. Você o 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
. ./findhardlinks.bashestar no Zsh do OS X. Minha janela atual na tela se fecha.
INUM=$(stat -c %i $1). Também NUM_LINKS=$(stat -c %h $1). Veja man statpara obter mais variáveis de formato que você pode usar.
ls -l
A primeira coluna representará 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) para o 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
inodeque, por sua vez, aponta para o conteúdo do disco.
Que tal o seguinte, mais simples? (Os últimos podem substituir os scripts longos acima!)
Se você possui um arquivo específico <THEFILENAME>e deseja conhecer todos os seus hardlinks espalhados pelo diretório <TARGETDIR>, (que pode até ser todo o sistema de arquivos indicado por /)
find <TARGETDIR> -type f -samefile <THEFILENAME>
Estendendo a lógica, se você quiser conhecer todos os arquivos nos <SOURCEDIR>vários links físicos espalhados <TARGETDIR>:
find <SOURCEDIR> -type f -links +1 \
-printf "\n\n %n HardLinks of file : %H/%f \n" \
-exec find <TARGETDIR> -type f -samefile {} \;
-type fporque o arquivo também pode ser um diretório.
.e ..nos diretórios são hardlinks. Você pode dizer quantos subdiretórios estão em um diretório a partir da contagem de links de .. Isso é discutível de qualquer maneira, já que find -samefile .ainda não imprimirá nenhuma subdir/..saída. find(pelo menos a versão GNU) parece estar codificado para ignorar .., mesmo com -noleaf.
O(n^2)executada finduma vez para cada membro de um conjunto de arquivos vinculados. find ... -printf '%16i %p\n' | sort -n | uniq -w 16 --all-repeated=separateiria funcionar, (16 não é grande o suficiente para uma representação decimal de 2 ^ 63-1, então quando seu sistema de arquivos XFS é grande o suficiente para ter números de inode que a alta, atente)
Existem muitas respostas com scripts para encontrar todos os hardlinks em um sistema de arquivos. A maioria deles faz coisas tolas, como a execução de localizar, para verificar todo o sistema de arquivos em -samefilebusca de CADA arquivo vinculado à multiplicação. Isso é loucura; tudo o que você precisa é escolher o número do inode e imprimir duplicatas.
Com apenas uma passagem pelo sistema de arquivos para encontrar e agrupar todos os conjuntos de arquivos vinculados
find dirs -xdev \! -type d -links +1 -printf '%20D %20i %p\n' |
sort -n | uniq -w 42 --all-repeated=separate
Isso é muito mais rápido que as outras respostas para encontrar vários conjuntos de arquivos com links físicos.
find /foo -samefile /baré excelente para apenas um arquivo.
-xdev: limite para um sistema de arquivos. Não é estritamente necessário, pois também imprimimos o FS-id para uniq em! -type ddiretórios de rejeição: as entradas .e ..significam que elas estão sempre vinculadas.-links +1 : contagem de links estritamente > 1-printf ...imprima o ID do FS, o número do inode e o caminho. (Com preenchimento para larguras de colunas fixas que podemos saber uniq.)sort -n | uniq ... classificação numérica e unificar nas 42 primeiras colunas, separando grupos com uma linha em brancoUsar ! -type d -links +1significa que a entrada da classificação é apenas tão grande quanto a saída final do uniq, portanto não estamos fazendo uma grande quantidade de classificação de string. A menos que você o execute em um subdiretório que contenha apenas um de um conjunto de links físicos. De qualquer forma, isso consumirá muito menos tempo de CPU ao atravessar o sistema de arquivos do que qualquer outra solução publicada.
saída de amostra:
...
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?: Desmarque a saída com awkou cut. uniqtem suporte de seleção de campo muito limitado, por isso, preencha a saída de localização e uso a largura fixa. 20chars é grande o suficiente para o número máximo possível de inode ou dispositivo (2 ^ 64-1 = 18446744073709551615). O XFS escolhe números de inodes com base em onde eles estão alocados no disco, e não contíguamente de 0, para que sistemas de arquivos XFS grandes possam ter números de inode> 32 bits, mesmo que não tenham bilhões de arquivos. Outros sistemas de arquivos podem ter números de inode de 20 dígitos, mesmo que não sejam gigantescos.
TODO: classifica grupos de duplicatas por caminho. Classificá-los por ponto de montagem, em seguida, o número do inode combina tudo, se você tiver alguns subdiretórios diferentes que possuem muitos hardlinks. (ou seja, grupos de grupos duplos andam juntos, mas a saída os mistura).
Uma final sort -k 3classificaria as linhas separadamente, não grupos de linhas como um único registro. O pré-processamento de algo para transformar um par de novas linhas em um byte NUL, e o uso do GNU sort --zero-terminated -k 3pode ajudar. trsó opera com caracteres únicos, mas não com padrões 2-> 1 ou 1-> 2. perlfaria isso (ou apenas analisaria e classificaria dentro de perl ou awk). sedtambém pode funcionar.
%Dé o identificador de sistema de arquivos (que é único para a inicialização atual, enquanto há sistemas de arquivos são umounted), de modo que se segue é ainda mais genérica: find directories.. -xdev ! -type d -links +1 -printf '%20i %20D %p\n' | sort -n | uniq -w 42 --all-repeated=separate. Isso funciona desde que nenhum diretório contenha outro diretório no nível do sistema de arquivos, mas também analisa tudo o que pode ser vinculado por hardware (como dispositivos ou softlinks - sim, os softlinks podem ter uma contagem de links maior que 1). Note que dev_te ino_ttem 64 bits hoje. Isso provavelmente será válido enquanto tivermos sistemas de 64 bits.
! -type d, em vez de -type f. Eu até tenho alguns links simbólicos vinculados no meu sistema de arquivos ao organizar algumas coleções de arquivos. Atualizei a minha resposta com a sua versão melhorada (mas eu coloquei o fs-id primeiro, então a ordem de classificação, pelo menos, grupos de sistema de arquivos.)
Isso é um comentário à própria resposta e roteiro de Torocoro-Macho, mas obviamente não cabe na caixa de comentários.
Reescreva 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
Tentei mantê-lo o mais semelhante possível ao seu para facilitar a comparação.
Deve-se sempre evitar a $IFSmagia se uma glob é suficiente, uma vez que é desnecessariamente complicada, e os nomes dos arquivos podem realmente conter novas linhas (mas, na prática, principalmente a primeira razão).
Você deve evitar a análise manual lse essa saída, tanto quanto possível, pois mais cedo ou mais tarde você será mordido. Por exemplo: na sua primeira awklinha, você falha em todos os nomes de arquivos que contêm espaços.
printfmuitas vezes salvará problemas no final, pois é muito robusto com a %ssintaxe. Também oferece controle total sobre a saída e é consistente em todos os sistemas, ao contrário echo.
stat pode economizar muita lógica nesse caso.
GNU find é poderoso.
Suas invocações heade tailpoderiam ter sido tratadas diretamente awkcom, por exemplo, o exitcomando e / ou a seleção na NRvariável. Isso salvaria as invocações do processo, que quase sempre melhoram o desempenho severamente em scripts de trabalho árduo.
Seus egreps poderiam muito bem ser justos grep.
find ... -xdev -type f -links +1 -printf '%16i %p\n' | sort -n | uniq -w 16 --all-repeated=separate. Isso é MUITO mais rápido, pois ele atravessa o fs apenas uma vez. Para vários FSes de uma só vez, você precisa prefixar os números dos inodes com um ID de FS. Talvez comfind -exec stat... -printf ...
Baseado no findhardlinksscript (renomeado para hard-links), é isso que refatorei e fiz funcionar.
Resultado:
# ./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 "";
Uma solução GUI fica muito próxima da sua pergunta:
Você não pode listar os arquivos vinculados reais de "ls" porque, como os comentaristas anteriores apontaram, os "nomes" do arquivo são meros aliases para os mesmos dados. No entanto, na verdade, existe uma ferramenta GUI que se aproxima muito do que você deseja, que é exibir uma lista de caminhos de nomes de arquivos que apontam para os mesmos dados (como hardlinks) no linux, chamada FSLint. A opção desejada está em "Confrontos de nomes" -> desmarque "caixa de seleção $ PATH" em Pesquisa (XX) -> e selecione "Aliases" na caixa suspensa após "para ..." na parte superior central.
O FSLint está muito mal documentado, mas descobri que a árvore de diretórios limitada em "Caminho de pesquisa" está marcada com a caixa de seleção selecionada para "Recurso?" 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 a pesquisa do programa.
Você pode configurar lspara destacar os hardlinks usando um 'alias', mas, como afirmado anteriormente, não há como mostrar a 'fonte' do hardlink, e é por isso que anexo .hardlinkpara ajudá-lo.
Adicione o seguinte em algum lugar do seu .bashrc
alias ll='LC_COLLATE=C LS_COLORS="$LS_COLORS:mh=1;37" ls -lA --si --group-directories-first'
link(2)chamada do sistema, não há sentido em qual é o original e o que é o link. É por isso que, como as respostas apontam, a única maneira de encontrar todos os links éfind / -samefile /a/A. Como uma entrada de diretório para um inode não "conhece" outras entradas de diretório para o mesmo inode. Tudo o que eles fazem é refcount o inode para que ele possa ser excluído quando o sobrenome forunlink(2)ed. (Esta é a "contagem de links" nalssaída).