Comando para verificar se o usuário atual tem permissão de gravação

3

Eu tenho que criar um script para verificar se o usuário atual tem permissão de gravação em um arquivo. Caso contrário, um erro deve aparecer.

Eu escrevi isto:

if [namei -m /path/to/textfile.txt | grep w]; then 
  echo "message"

Mas parece que recebi um erro de sintaxe.

    
por Diqn Raikov 27.11.2017 / 11:06

1 resposta

5

Vamos analisar os problemas com seu código. Como sobremesa mencionada em um comentário , o primeiro problema é a sintaxe do comando [ . Precisamos colocar espaços entre [ e seus argumentos, porque o shell usa espaços para separar campos e pensa que [namei é o comando que você deseja executar.

Vou usar um arquivo no meu diretório pessoal chamado file , no qual sei que tenho permissão de gravação, em meus exemplos. Eu coloquei seu código em uma linha, para facilitar o teste de forma interativa. Ele funcionará da mesma maneira como se houvesse uma nova linha após then .

$ if [namei -m playground | grep w]; then echo "writeable"
No command '[namei' found, did you mean:
 Command 'namei' from package 'util-linux' (main)
[namei: command not found

Vamos corrigir os espaços em torno de [ e ] :

$ if [ namei -m playground | grep w ]; then echo "writeable"
>

Agora recebo uma solicitação para digitar algo, um > . O prompt me diz que o shell está esperando por mim para inserir algo. A forma mais simples da sintaxe de if é

if condition; then command; fi

para que o shell aguarde o fi . Se eu entrar no prompt, eu entendo isso:

$ if [ namei -m file | grep w ]; then echo "writeable"
> fi
bash: [: missing ']'
grep: ]: No such file or directory

Parece que o canal | está causando problemas aqui, pois [ não pode encontrar seu último argumento e grep acha que seu último argumento é ] . Como [ (ou o que estamos usando aqui de qualquer maneira) é um shell embutido, nós poderemos obter algumas informações sobre ele usando help

$ help [
[: [ arg... ]
    Evaluate conditional expression.

    This is a synonym for the "test" builtin, but the last argument must
    be a literal ']', to match the opening '['.

Não podemos usar um pipe no meio dos argumentos de um comando. Em outras situações, poderíamos colocar os comandos em um subshell colocando-os em ( ) , mas esse é um erro de sintaxe em [ (e test ).

O problema real aqui é que o que estamos tentando passar para o comando [ não é algo que possa ser avaliado como verdadeiro ou falso. Se o argumento que você tentar passar para test for um comando, test não usará o status de saída desse comando como acredito que você esteja esperando. Você pode passar a saída de um comando para [ usando substituição de comando , mas não é isso que você ou seu código querem fazer.

Acho que o seu código está tentando verificar se grep encontrou w na saída de namei -m somefile . Nós não precisamos do comando test para isso.

$ help if
if: if COMMANDS; then COMMANDS; [ elif COMMANDS; then COMMANDS; ]... [ else COMMANDS; ] fi
    Execute commands based on conditional.

   The 'if COMMANDS' list is executed.  If its exit status is zero, then the
   'then COMMANDS' list is executed.  Otherwise, each 'elif COMMANDS' list is
   executed in turn, and if its exit status is zero, the corresponding
   'then COMMANDS' list is executed and the if command completes.  Otherwise,
   the 'else COMMANDS' list is executed, if present.  The exit status of the
   entire construct is the exit status of the last command executed, or zero
   if no condition tested true.

Portanto, se estivermos interessados apenas em saber se um comando é bem-sucedido, podemos colocar o comando como uma condição para if :

$ if namei -m file | grep w; then echo "writeable"; fi
 -rw-rw-r-- file
writeable

Você pode até usar -q para suprimir a saída de grep e coletar apenas o status de saída (sucesso se uma correspondência for encontrada):

$ if namei -m file | grep  -q w; then echo "writeable"; fi
writeable

Mas isso não é uma boa maneira de testar se o arquivo é gravável por você. Vamos tentar outro arquivo de teste:

$ touch file_with_w
$ chmod 444 file_with_w
$ stat -c %A file_with_w 
-r--r--r--
$ if namei -m file_with_w | grep  -q w; then echo "writeable"; fi
writeable

Se analisarmos a saída de namei -m para um arquivo com w em seu nome, esse método fará com que pareça gravável, mesmo que seja somente leitura para todos.

Analisar a saída de comandos às vezes é o caminho certo para obter as informações desejadas. Mas geralmente há uma maneira melhor, na forma de uma opção para esse comando, ou um comando diferente com um propósito similar.

Vamos voltar ao comando test aka [ e ver se tem alguma opção útil. Você pode inserir help test ou, para obter mais detalhes, leia a seção Expressões Condicionais do manual de Bash

File operators:
...
   -w FILE        True if the file is writable by you.

Aha! o comando test tem exatamente o que queremos, como mencionado em resposta a Verificando se há um arquivo e se ele pode ser lido e gravado

$ if [ -w file ]; then echo "writeable"; fi
writeable
$ if [ -w file_with_w ]; then echo "writeable"; fi
$ 

Isso mesmo:)

Mas você mencionou que queria que o comando emitisse uma mensagem de erro se o arquivo não fosse gravável, em vez de uma instrução que é gravável. Para isso, precisamos de uma declaração else

$ if [ -w file_with_w ]; then echo "writeable"; else echo "not writeable"; fi
not writeable

Como um script, você poderia escrever esse comando assim:

#!/bin/bash

if [ -w "" ]; then
   echo "writeable"
else
   echo "not writeable"
fi

Em seguida, você pode conceder permissão de execução (substitua script pelo nome real do arquivo)

chmod u+x script

e execute-o com o arquivo que você deseja testar como argumento (referenciado no script com ):

$ ./script file
writeable
$ ./script file_with_w
not writeable

Se você apenas quiser receber uma mensagem de erro quando o arquivo não for gravável e não tiver saída quando estiver, você poderá negar a condição de teste em vez de escrever outra:

$ if [ ! -w file_with_w ]; then echo "not writeable"; fi
not writeable

Como Panther mencionou em a comentar , você também pode querer usar a variável $USER , que deve se expandir para o nome do usuário que está executando o shell. Você pode, portanto, criar uma mensagem de erro mais impressionante:

$ if [ ! -w file_with_w ]; then echo "file is not writeable by $USER"; fi
file is not writeable by zanna

Para comandos simples de test , você também pode usar [ e test e [[ sem if e usar operadores shell para a lógica:

$ [ -w file_with_w ] || echo "not writeable"
not writeable

|| é o OR lógico do shell.Significa se o comando anterior falhou, então execute o próximo comando

O AND lógico do shell é && :

$ [ ! -w file_with_w ] && echo "not writeable"
not writeable

&& significa se o comando anterior foi bem sucedido, então execute o próximo comando

Tudo isso funciona porque o comando test fornece um status de saída útil, conforme descrito em help test :

Exit Status:
Returns success if EXPR evaluates to true; fails if EXPR evaluates to
false or an invalid argument is given.
    
por Zanna 27.11.2017 / 17:19