Como testar de forma não invasiva o acesso de gravação a um arquivo?

20

Em um script de shell, como faço para testar de maneira fácil e não invasiva o acesso de gravação a um arquivo sem realmente tentar modificá-lo?

Eu poderia analisar a saída de stat, mas isso parece realmente complexo e talvez quebradiço, embora não tenha certeza de quanto a saída de estatísticas difere nas implementações e no tempo.

Eu poderia acrescentar ao final do arquivo e ver se isso foi bem-sucedido, mas isso é potencialmente perigoso, por duas razões em que consigo pensar:

  1. Agora tenho que remover a adição e, caso algum outro processo seja gravado no arquivo, isso imediatamente se tornará não trivial, pois minha linha não é mais a última.
  2. Qualquer processo de leitura do arquivo pode ter requisitos arbitrários no conteúdo desse arquivo, e eu posso simplesmente ter quebrado esse aplicativo.
user50849
fonte

Respostas:

29

Basta usar o wsinalizador - da testutilidade:

[ -w /path/to/file ] && echo "writeable" || echo "write permission denied"

Observe que, se você for gravar no arquivo posteriormente, ainda é possível que não seja possível gravá-lo. O arquivo pode ter sido movido, as permissões podem ter sido alteradas etc. Também pode acontecer que -wdetecte permissões de gravação, mas outro fator intervém para tornar o arquivo não gravável .

caos
fonte
11
Claro! Eu deveria ter pensado em verificar a página de manual do teste. Obrigado.
user50849
11
@qweilun é um builtin shell, mas você pode exibir a página homem via man testouman [
caos
5
@chaos É tanto um builtin shell e um link externo executável - tentativatype -a
Volker Siegel
11
Pela fontetest usa euidaccessque simplesmente verifica os bits de permissão . Não existem outros fatores (por exemplo, SELinux) que poderiam proibir o acesso de gravação?
Zamnuts
2
@BroSlow, &&e ||têm a mesma precedência. Eles são avaliados da esquerda para a direita.
Curinga
11

Outra abordagem:

if >> /path/to/file
then
    echo "writeable"
else
    echo "write permission denied"
fi

Isso tentará abrir o arquivo para anexar e, se tiver êxito, execute não nenhum comando (ou seja, execute um comando nulo ) com saída para o arquivo. 

Cuidado, pois isso cria um arquivo vazio, se não existir.

O -woperador do testcomando pode apenas fazer umastat e tentar descobrir se parece que você deve ter acesso. Minha alternativa (acima) é mais confiável do que a testabordagem em algumas condições especiais, porque força a verificação de acesso a ser feita pelo kernel e não pelo shell. Por exemplo,

  • se o arquivo estiver em um sistema de arquivos não Unix - especialmente se for montado remotamente a partir de um servidor de arquivos não Unix - porque stat poderá retornar um valor de modo enganoso.
  • se o arquivo estiver em um sistema de arquivos montado somente leitura.
  • se o arquivo tiver uma ACL e o modo parecer que você deveria ter acesso, mas a ACL nega ou vice-versa.
  • se alguma estrutura de segurança (AppArmor, SELinux,…) negar acesso ao arquivo.
G-Man Diz 'Reinstate Monica'
fonte
3
Acabei de testar isso (no Debian). Nenhum dos tempos foi alterado, e é assim que deve funcionar em qualquer Unix. O tempo de acesso deve ser atualizado apenas se você ler o arquivo; o tempo de modificação deve ser atualizado apenas se você gravar no arquivo. Este código também não. @ Schwern: você tem uma referência para sua declaração? Algum de vocês já tentou?
G-Man diz 'Reinstate Monica'
2
PS @muru: Eu apenas tentei touchum arquivo que eu possuía, mas não tinha acesso de gravação, e foi bem-sucedido. Acho que chmodé o arquivo e chmodo devolvemos. Portanto, touchparece ser absolutamente inútil como resposta à pergunta.
G-Man diz 'Reinstate Monica'
2
@ G-Man ah, isso é interessante. O IIRC vimtem esse comportamento de alterar rapidamente as permissões quando forçado a gravar em arquivos somente leitura. Eu verifiquei com strace, touch's openfalha com EACCES, mas a chamada subsequente para utimensatbem-sucedido, que é por isso que eu acho que touchem todo o saídas com sucesso.
Muru
2
@ muru: Obrigado por verificar isso. utimensat(2)diz: “ Requisitos de permissão: 1. acesso de gravação (ou) 2. o ID do usuário efetivo do chamador deve corresponder ao proprietário do arquivo,….”
G-Man diz 'Reinstate Monica'
3
Outros problemas, como os de Champignac: >> filenão é portátil (por exemplo, executa o NULLCMD no zsh), use em true >> filevez disso. E se o arquivo é um pipes nomeados, ele tem efeitos colaterais desagradáveis.
Stéphane Chazelas
3

G-man está certo: [ -w ]nem sempre dirá a verdade. Aqui para lidar com arquivos inexistentes e com a permissão negada da shell:

( [ -e /path/to/file ] && >> /path/to/file ) 2> /dev/null && 
  echo writable || 
  echo not writable

Atualizar : Parece assustador, não é? Bem, é sim. Hmm ... como expressá-lo ... NÃO USE ISSO, a menos que você saiba perfeitamente que está nas condições que ele solicita para funcionar como esperado. Veja o comentário de Stephane.

O que concluir então? Mesmo [ -w ]que não diga a verdade, é o único comando que se destina a fazer o trabalho. Se isso não acontecer, culparemos, escreveremos relatórios de bugs e funcionará no futuro. Melhor verificar as condições sob as quais ele trabalha e usa [ -w ]; escreva código especial para casos especiais. As soluções alternativas têm suas próprias condições.

[ -w /path/to/file ]

é o melhor a priori .

Champignac
fonte
3
Se o arquivo for um pipe nomeado, ele será interrompido se não houver leitura e, mesmo se houver um leitor, haverá efeitos colaterais desagradáveis. test -wna maioria das implementações, o uso access(2)deve ser suficiente para testar permissões.
Stéphane Chazelas