Dois arquivos estão vinculados?

27

Como posso saber se dois arquivos estão vinculados na linha de comando? por exemplo, algo vincula isso:

$ ls
fileA fileB fileC

$ is-hardlinked fileA fileB
yes

$ is-hardlinked fileA fileC
no
Vincent Scheib
fonte

Respostas:

37

Na maioria dos sistemas de arquivos¹, um arquivo é determinado exclusivamente por seu número de inode ; portanto, tudo que você precisa verificar é se os dois arquivos têm o mesmo número de inode e se estão no mesmo sistema de arquivos.

Ash, ksh, bash e zsh têm uma construção que faz a verificação para você: o operador de igualdade de arquivos -ef.

[ fileA -ef fileB ] && ! [ fileA -ef fileC ]

Para casos mais avançados, ls -i /path/to/filelista o número do inode de um arquivo. df -P /path/to/filemostra em que sistema de arquivos o arquivo está (se dois arquivos estiverem no mesmo diretório, eles estão no mesmo sistema de arquivos). Se o seu sistema possuir o statcomando, provavelmente poderá mostrar os números do inode e do sistema de arquivos ( statvaria de sistema para sistema, verifique sua documentação). Se você quiser ver rapidamente os links físicos dentro de um diretório, tente ls -i | sort(possivelmente direcionado para o awk ).

¹ Todos os sistemas de arquivos unix nativos e alguns outros como NTFS, mas possivelmente não casos exóticos como o CramFS.

Gilles 'SO- parar de ser mau'
fonte
E definitivamente não em nada baseado em FAT, onde seria detectado como um arquivo "reticulado".
Ignacio Vazquez-Abrams,
4
Observe que fileA -ef fileBtambém retorna 0(êxito) se fileAfor um link simbólico para fileB, ou vice-versa, ou ambos os links para o mesmo arquivo.
janmoesen
como você realmente executa o comando sugerido? Eu tentei [.bashrc -ef .bash / .bashrc] e variações disso, mas realmente não funcionou.
Charlie Parker
@CharlieParker [ .bashrc -ef .bash/.bashrc ]está correto. Sem contexto, é claro, não tenho idéia do por que "realmente não funcionou" - você pode comparar os arquivos errados, não verificar o resultado corretamente, usar um shell sem -ef, ...
Gilles 'SO- pare de ser mau'
2
@CharlieParker O comando é realmente [e é sinônimo de test. Mas man [ou man testfornecerá a página de manual do comando externo, enquanto quase todos os shell existentes têm um comando interno com opções ligeiramente diferentes, portanto, você deve procurar este no manual do shell.
Gilles 'SO- stop be evil'
4
function is-hardlinked() {
    r=yes
    [ "`stat -c '%i' $1`" != "`stat -c '%i' $2`" ] && r=no
    echo $r
}
x-way
fonte
6
Observe que isso pode ser um falso positivo se os dois arquivos estiverem em sistemas de arquivos diferentes, mas tiverem o mesmo inode. Você também precisa testar o número do dispositivo ( stat -c %d). E se você estiver no Linux (dado seu statcomando), seu shell deve [ fileA -ef fileB ]fazer tudo isso diretamente. Além disso, seu comando quebra gratuitamente com nomes de arquivos que contenham espaços em branco ou \[?*, ou começa com -: sempre coloque aspas duplas em torno do comando susbtitutions ( "$(stat -c %i -- "$1")").
Gilles 'SO- stop be evil'
11
Por que você usaria um monte de construções pesadas, mas portáteis e, em seguida, a functionpalavra - chave extremamente portátil, com um nome de função que (por conter um traço) viola as convenções POSIX em nomes permitidos?
Charles Duffy
Você esqueceu de citar seu $1e $2. Você também pode usar a $()sintaxe em vez de backticks, porque os colchetes deixam claro onde o comando começa e onde termina e o aninhamento é mais simples.
Josch
3

Como o primeiro pôster sugere, você pode escrever um script baseado em algo como isto no Linux:

stat -c '%i' fileA fileB fileC
Agora não
fonte
4
Isso não é suficiente: você obterá o mesmo número para os dois arquivos se estiver em sistemas de arquivos diferentes, mas tiver o mesmo inode. Você também precisa testar o número do dispositivo ( stat -c %d). E se você estiver no Linux (dado seu statcomando), seu shell deve [ fileA -ef fileB ]fazer tudo isso diretamente.
Gilles 'SO- stop be evil'
0

Com o GNU find(1)versão 4.2.11 ou mais recente, você também pode usar este:

if [ "yes" = "$(find fileA -samefile fileB -exec echo yes \;)" ]; then
    echo yes
else
    echo no
fi

Se fileAfor o mesmo arquivo fileB, findele imprimirá "yes" e a condição se tornará verdadeira.

Ao contrário do uso do operador de igualdade de arquivos, -efisso gerará um novo processo.

Josch
fonte