Como encontrar em qual dispositivo um arquivo está (e usar isso em um script)?

3

Eu quero descobrir em qual dispositivo meu arquivo está, para que eu possa usá-lo em um script. Eu posso chegar até aqui:

$ df  .
Filesystem   512-blocks      Used Available Capacity  Mounted on
/dev/disk0s2  498438976 294369520 203557456    60%    /

mas esta saída parece muito desajeitada; existe uma maneira melhor do que analisar isso para obter a primeira 'palavra' da segunda linha?

O que eu realmente preciso é algo assim para que eu possa canalizar para o próximo comando:

$ somecommand .
/dev/disk0s2

Como posso conseguir isso, de preferência sem recorrer a uma string para hackear a saída 'df'?

    
por antonyh 22.02.2013 / 13:26

5 respostas

3

Você pode fazer isso apenas com o shell (funciona em bash , dash , ksh , zsh ):

df . | (read a; read a b; echo "$a")

Ou se a saída não for necessária (o resultado será mantido em $ a) e seu shell suportará a substituição do processo (como bash , zsh ):

{ read; read a b;}< <(df .)

E aqui estão algumas comparações com a velocidade das outras soluções:

# pure shell solution 1

bash-4.2$ time for i in $(seq 500); do df . | (read a; read a b; echo "$a"); done > /dev/null
1.899

(dash) $ time -f '%e' dash -c 'for i in $(seq 500); do df . | (read a; read a b; echo "$a"); done > /dev/null'
1.05

(ksh) $ time for i in $(seq 500); do df . | (read a; read a b; echo "$a"); done > /dev/null
    0m1.16s real     0m0.02s user     0m0.12s system

(zsh) manatwork% time (for i in $(seq 500); do df . | (read a; read a b; echo "$a"); done > /dev/null)
1.51s

# pure shell solution 2

bash-4.2$ time for i in $(seq 500); do { read; read a b;}< <(df .); done
1.192

(zsh) manatwork% time (for i in $(seq 500); do { read; read a b;}< <(df .); done)
3.51s

# other solutions

bash-4.2$ time for i in $(seq 500); do df . | tail -1 | cut -f 1 -d " "; done > /dev/null
1.405

bash-4.2$ time for i in $(seq 500); do df . | sed '2!d' | awk '{print $1}'; done > /dev/null
5.407

bash-4.2$ time for i in $(seq 500); do df . | sed -n '2{s/ .*$//;p}'; done > /dev/null
1.767

bash-4.2$ time for i in $(seq 500); do df . | sed '2!d' | awk '{print $1}'; done > /dev/null
3.334

bash-4.2$ time for i in $(seq 500); do df . | gawk 'NR==2{print $1}'; done > /dev/null
3.013

bash-4.2$ time for i in $(seq 500); do df . | mawk 'NR==2{print $1}'; done > /dev/null
1.747

bash-4.2$ time for i in $(seq 500); do df . | perl -nae 'print$F[0]if$.==2'; done > /dev/null
2.752

(Não comparado com a solução stat , pois não funciona aqui.)

    
por 22.02.2013 / 17:53
3

É a maneira comum no UNIX para concatenar os poderes de programas simples que um pouco. Portanto, não se preocupe em canalizar a saída de df através de algum filtro.

df /path/to/file | sed -n '2{s/ .*$//;p}'

-n suprime as linhas de impressão automaticamente, 2{} executa os comandos incluídos na segunda linha, s/ .*$// descarta tudo do primeiro espaço, p imprime o que resta. Adicionando q após o p nos casos em que um analisa entradas mais longas e apenas quer que a segunda (ou n-ésima) linha possa acelerar um pouco também.

    
por 22.02.2013 / 13:46
1

Você pode usar uma linha simples com sed , awk as

df . | sed '2!d' | awk '{print $1}'

Em sed , especificando 2d mean exclua a linha 2 nd . Adicionar um ! nega isso, então apenas apaga todas as outras linhas e imprime a segunda linha. O comando awk exibe o primeiro valor da coluna.

Saída:

/dev/disk0s2
    
por 22.02.2013 / 13:38
1

A análise da saída de df é o melhor que você pode fazer portavelmente. Passe -P para df para evitar a formatação da saída de uma maneira estranha (provavelmente você está seguro em todos os lugares, já que está pegando o primeiro campo, mas precisa de -P para capturar o ponto de montagem, pois pode ser relegado a uma linha subsequente se as colunas anteriores forem muito largas).

device_name=$(df -P . | awk 'NR==2 {print $1}')

Observe que alguns sistemas permitem que nomes de dispositivos contenham espaços em branco (o IIRC tende a acontecer no OSX). Não há maneira portátil ou conveniente de lidar com este caso.

Eu não acho que haja uma maneira melhor de fazer isso no Linux. stat pode fornecer o número do dispositivo ( stat -c %t . ), mas se você quiser uma entrada de dispositivo em /dev , é necessário extraí-lo de /proc , o que df faz melhor.

    
por 22.02.2013 / 18:38
0

Se você estiver usando o linux, você pode fazê-lo com findmnt (parte do util-linux package) "sem recorrer ao hacking de string" :

findmnt -no source -T /path/to/file
/dev/sda1

Ao usar a opção

-T, --target path
se o caminho não for um arquivo ou diretório de ponto de montagem, findmnt verifica elementos de caminho na ordem inversa para obter o ponto de montagem. As outras duas opções suprimem a linha de cabeçalho: -n, --noheading e selecionam a (s) coluna (s) a ser listada: -o, --output

df de coreutils tem uma opção semelhante --output= para imprimir apenas determinados campos, como source , por exemplo:

df --output=source /path/to/file
Filesystem
/dev/sda1

não há opção para remover o cabeçalho. Se isso for um problema, você terá que fazer alguns string hacking , por exemplo. canalize-o para sed 1d

    
por 04.05.2016 / 13:53