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.