Imprimindo o arquivo com o número de hardlinks

1

Eu posso imprimir o número de hardlinks para arquivos no diretório usando find . type f -printf "%f %n\n" , mas isso também irá imprimir o hardlink não apenas arquivos originais:

Exemplo:   file1 é um arquivo original.   O hardlink1 é um hardlink para o arquivo original1.

Usando este código, ele será impresso a seguir:

file1 2 hardlink1 2

Eu quero que esse problema seja resolvido usando apenas find . Quero imprimir apenas o arquivo original.

    
por pnom 03.05.2016 / 15:12

1 resposta

2

Você entendeu mal como os hard links funcionam. Não há original. Todos os arquivos são simplesmente hardlinks para um inode . Portanto, os hardlinks não vinculam a arquivos, eles se ligam a inodes.

Para ilustrar, considere este arquivo:

$ touch file
$ ls -li file
3282140 -rw-r--r-- 1 terdon terdon 0 May  3 16:27 file

Como você pode ver acima, file aponta para o inode 3282140 . Agora, se criarmos um link para ele:

$ ln -s file softlink
$ ls -li 
3282140 -rw-r--r-- 1 terdon terdon 0 May  3 16:27 file
3282141 lrwxrwxrwx 1 terdon terdon 4 May  3 16:29 softlink -> file

O softlink está apontando para file , mas o próprio link (que também é um objeto do sistema de arquivos, outro "arquivo") tem um inode diferente ( 3282141 ). No entanto, se criarmos um link físico, ele compartilhará o mesmo inode:

$ ln file hardlink
$ ls -li
total 0
3282140 -rw-r--r-- 2 terdon terdon 0 May  3 16:27 file
3282140 -rw-r--r-- 2 terdon terdon 0 May  3 16:27 hardlink
3282141 lrwxrwxrwx 1 terdon terdon 4 May  3 16:29 softlink -> file

Então, se eu adicionar agora algum texto a hardlink , é exatamente o mesmo que adicionar texto a file :

$ echo "foo" > hardlink 
$ cat hardlink 
foo
$ cat file
foo

E, como softlink está apontando para file , veremos o conteúdo de file se eu cat it:

$ cat softlink 
foo

O mesmo acontece se eu adicionar texto a file , hardlink e file são equivalentes:

$ echo bar >> file
$ cat hardlink 
foo
bar

Agora, se eu excluir file , softlink será um link quebrado, mas hardlink não será afetado:

$ rm file 
$ ls -li
total 4
3282140 -rw-r--r-- 1 terdon terdon 8 May  3 16:33 hardlink
3282141 lrwxrwxrwx 1 terdon terdon 4 May  3 16:29 softlink -> file
$ cat softlink 
cat: softlink: No such file or directory

Como o alvo do link foi removido, o softlink está corrompido. O hardlink, no entanto, ainda está lá, já que apontava para o mesmo inode:

$ cat hardlink 
foo
bar

Tudo isso é para dizer que simplesmente não há como diferenciar um hardlink do arquivo para o qual ele foi criado, porque, diferente dos softlinks, ele não foi realmente criado apontando para um arquivo. Todos os arquivos são hardlinks apontando para um inode do sistema de arquivos. De fato, excluir um arquivo simplesmente remove o link para o inode. Na verdade, não remove os dados. O sistema mantém uma contagem dos links apontando para cada inode e simplesmente considera inodes disponíveis para escrita se a contagem de links for 0.

O que você pode fazer é encontrar todos os links apontando para um inode e excluir todos, exceto um. Se voltarmos para onde estávamos no começo:

$ rm *
$ touch file
$ ln file hardlink
$ ls -l file hardlink
-rw-r--r-- 2 terdon terdon 0 May  3 16:39 file
-rw-r--r-- 2 terdon terdon 0 May  3 16:39 hardlink
           ^
           |---- the number of links

A saída de ls -l inclui o número de links apontando para um inode. Portanto, você pode iterar sobre sua saída (esse é um dos poucos casos em que a análise de ls é segura) e excluir qualquer arquivo com um número de link > 1:

for file in *; do [ $(ls -l $file | cut -d' ' -f2) -gt 1 ] && rm "$file"; done

Isso excluirá todos os hardlinks, exceto um, desde que todos os hardlinks estejam no mesmo diretório.

Outras leituras: link

    
por 03.05.2016 / 15:52