Verifique se 2 diretórios estão hospedados na mesma partição no Linux


9

Como posso verificar se /my/direstá na mesma partição que /?

Isto é para integração dentro de um script. As montagens de ligação devem ser manuseadas corretamente. As soluções compatíveis com POSIX são bem-vindas.


"As montagens de encadernação devem ser manuseadas corretamente." Mas o que você considera correto? Sua pergunta pode ser interpretada de qualquer maneira.
Gilles 'SO- stop be evil'

@ Gilles No título original, escrevi "hospedado" em vez de "montado", alguém editado adicionando confusão IMHO. No entanto, meu corpo de perguntas é claro: "na mesma partição", ou seja, na mesma partição física, seja qual for o caminho ou ponto de montagem usado para acessar os dois arquivos / diretórios.
30614 Totor

Respostas:


6

Você pode verificar isso com stat:

$ stat -c '%d %m' /proc/sys/
3 /proc

Mostra o número do dispositivo e onde seu diretório foi montado.


1
Bom, mas o statcomando shell não é POSIX ...
Totor

Não? Como você sabe?

Não está nesta lista .
Totor 21/03

Oh culpa minha. Mas da próxima vez, mostre esse link com antecedência.

5

O comando a seguir fornece um nome exclusivo para o ponto de montagem que contém o arquivo $file:

df -P -- "$file" | awk 'NR==2 {print $1}'

Isso funciona em qualquer sistema POSIX . A -Popção impõe um formato previsível; o primeiro campo da segunda linha é o "nome do sistema de arquivos". Portanto, para verificar dois arquivos estão no mesmo ponto de montagem:

if [ "$(df -P -- "$file1" | awk 'NR==2 {print $1}')" = \
     "$(df -P -- "$file2" | awk 'NR==2 {print $1}')" ]; then
  echo "$file1 and $file2 are on the same filesystem" ; fi

Ou, para salvar algumas invocações de processo:

if df -P -- "$file1" "$file2" |
   awk 'NR!=1 {dev[NR] = $1} END {exit(dev[2] != dev[3])}'; then
  echo "$file1 and $file2 are on the same filesystem" ; fi

Alguns sistemas operacionais podem ter espaços nos nomes dos volumes. Não há uma maneira completamente confiável de analisar a dfsaída neste caso.

Sob o capô, você pode identificar o sistema de arquivos que contém um arquivo pelo st_devcampo retornado por stat. Não há maneira portátil de fazer isso a partir de um script de shell. Alguns sistemas têm um statutilitário, mas sua sintaxe varia:

  • No Linux não incorporado, Cygwin ou outros sistemas com GNU coreutils, statrelata o st_devcampo quando chamado como stat -c %D -- "$file".
  • Algumas instalações do BusyBox incluem uma statcompatível com os coreutils GNU. Outros têm statsem a %copção; você pode usar, stat -t -- "$file" | awk '{print $8}'mas isso só funcionará se o nome do arquivo não contiver espaço em branco ou stat -t -- "$file" | awk 'END {print $(NF-8)}'lidar com nomes arbitrários de arquivos, mas não com futuras adições de campos à statsaída.
  • Os sistemas BSD têm um statutilitário diferente que requer stat -f %d -- "$file".
  • Solaris, AIX e outros não têm statutilidade.

Se o Perl estiver disponível, você poderá usar

perl -e 'print ((stat($ARGV[0]))[0])' -- "$file"

e para fazer a comparação:

perl -e 'exit((stat($ARGV[0]))[0] != (stat($ARGV[1]))[0])' -- "$file1" "$file2"

Observe que existem alguns casos de canto em que o resultado desejado não é claro. Por exemplo, com montagens bind do Linux, depois de mount --bind /foo /bar, /fooe /barsão considerados o mesmo sistema de arquivos. Sempre é possível que os dois arquivos estejam realmente localizados no mesmo dispositivo, mas você nunca saberá: por exemplo, se os arquivos estiverem em duas montagens de rede diferentes, o cliente não terá como saber se o servidor está exportando sistemas de arquivos diferentes.

Se os arquivos são diretórios e você pode gravá-los, outro método é criar um arquivo temporário e tentar criar um link físico. Este relata um resultado negativo nas montagens de ligação do Linux.

tmp1=$(TMPDIR=$dir1 mktemp)
tmp2=$(TMPDIR=$dir2 mktemp)
if ln -f -- "$tmp1" "$tmp2"; then
  echo "$dir1 and $dir2 are on the same filesystem, which supports hard links"
fi
rm -f "$tmp1" "$tmp2"

Problema: dfnem sempre fornece o nome do dispositivo, mas às vezes um link simbólico para ele, como /dev/disk/by-uuid/ca09b761-ae1b-450f-8a46-583327b48fb4tornar dfnão confiável. Até agora, a única opção confiável é usar uma statsolução baseada em.
Totor 30/04

@ Motor Isso não importa: qualquer que seja o nome dfrelatado para o dispositivo, ele é consistente entre as duas invocações; portanto, é bom fazer uma comparação.
Gilles 'SO- stop be evil'

Não, não funciona, eu testei. No Debian Wheezy, aqui, um único dfrelatório /dev/sda6e /dev/disk/by-uuid/ca09b..., ambos referentes ao mesmo dispositivo, mas com pontos de montagem diferentes. O teste de comparação de cadeias obviamente falha ao tentar com arquivos de cada ponto de montagem.
30614 Totor

@ Motor Normalmente, você não pode ter o mesmo dispositivo de bloco montado duas vezes. Como indico na minha resposta, há casos de canto, como montagens de ligação, que podem ou não ser relatados como distintos.
Gilles 'SO- stop be evil'

No entanto, funciona perfeitamente no Debian Squeeze e no Wheezy: mount /dev/sda6 /mnt1seguido de mount /dev/sda6 /mnt2trabalhos como um encanto. cat /proc/mountsestá bem com isso. No entanto, somente a partir do Wheezy /dev/disk/by-uuid/ca09b...é mostrada dfcomo o dispositivo para o sistema de arquivos raiz. Tentativas adicionais de montá-lo usando este simlink ou a UUID=ca09b...sintaxe mount não terminam mostrando nada além de /dev/sda6in df(não sei como reproduzir o que ele fez durante o processo de inicialização, mas essa não é a preocupação aqui).
30614 Totor

4
test $(df -P $path1 $path2 | awk '{if (NR!=1) {print $6}}' | uniq | wc -l) -eq 1

Funciona com qualquer número de caminhos.


Analisando a saída de dfé não sempre uma boa idéia .
Joseph R.

1
@ Motor Estou verificando o ponto de montagem ( $6), não o nome do dispositivo ( $1), para que não seja um problema.
n.st

1
@ JosephphR É o melhor que existe no POSIX. n.st: por que não verificar o primeiro campo? Não importa qual caminho foi usado para acessar o dispositivo, se for o mesmo ponto de montagem, a saída será consistente.
Gilles 'SO- stop be evil'

Isso não funciona com montagens de ligação.
30614 Totor

0

A melhor solução infalível disponível no POSIX é a comparação dos IDs de dispositivos dos arquivos fornecidos pela função stat (2) .

Perl tem uma função stat semelhante à que Gilles apontou :

perl -e 'exit((stat($ARGV[0]))[0] != (stat($ARGV[1]))[0])' -- file1 file2

mas a "maneira POSIX" é usar um programa C como:

./checksamedev file1 file2

qual código fonte é o seguinte:

#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>

int main(int argc, char* argv[]) {
    struct stat s1, s2;
    if( argc==3 && lstat(argv[1], &s1)==0 && lstat(argv[2], &s2)==0 )
        return !(s1.st_dev == s2.st_dev);
    return 2;
}

Se os IDs de dispositivo dos dois arquivos forem iguais, eles serão hospedados no mesmo sistema de arquivos; nesse caso, os comandos acima retornarão 0 (outro valor, caso contrário). Verifique com echo $?.

Isso funciona bem com montagens de ligação, mas provavelmente não funcionará com montagens de rede.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.