Como verificar se existe um arquivo em um script de shell

175

Eu gostaria de escrever um script de shell que verifique se um determinado arquivo archived_sensor_data.jsonexiste, e, se houver, o exclui. Seguindo http://www.cyberciti.biz/tips/find-out-if-file-exists-with-conditional-expressions.html , tentei o seguinte:

[-e archived_sensor_data.json] && rm archived_sensor_data.json

No entanto, isso gera um erro

[-e: command not found

quando tento executar o test_controllerscript resultante usando o ./test_controllercomando O que há de errado com o código?

Kurt Peek
fonte
2
Você deve definir um ou mais espaços em branco entre a abertura colchete "[" e opção "-e" mesmo que entre filename e fechar colchete "]"
Konstantin Yaniv

Respostas:

349

Está faltando um espaço necessário entre o suporte e -e:

#!/bin/bash
if [ -e x.txt ]
then
    echo "ok"
else
    echo "nok"
fi
chris01
fonte
12
Finalmente adicionou dois espaços em branco, um após o colchete e uma abertura antes do um fechamento: [ -e archived_sensor_data.json ] && rm archived_sensor_data.json. O script parece funcionar agora.
Kurt Peek
3
Isso também funciona usando if [ -e "$1" ](argumento de entrada do nome do arquivo).
Edward
2
A principal diferença aqui é o fato de você estar usando scripts "bash" em vez de scripts "shell". Observe que a primeira linha que você adicionou foi #! / Bin / bash; portanto, você está dizendo à máquina para usar "bash" em vez de sh. Porque sh não reconhecer que o argumento "-e"
Nick Cuevas
29

Aqui está um método alternativo usando ls:

(ls x.txt && echo yes) || echo no

Se você deseja ocultar qualquer saída, lspara ver apenas sim ou não, redirecione stdoute stderrpara /dev/null:

(ls x.txt >> /dev/null 2>&1 && echo yes) || echo no
Philip Kirkbride
fonte
1
Este código significa: "se lsfor bem-sucedido, existe esse arquivo, caso contrário, não há". Se lsfalhar, isso não significa que o arquivo está ausente. Pode haver algum outro erro. Por exemplo, crie um arquivo no diretório de propriedade do root e tente fazê-lo lscomo usuário comum. Ele falhará Permission denied, o que não é equivalente ao fato de o arquivo não existir.
Tigran
9

O pano de fundo da minha recomendação de solução é a história de um amigo que, até a segunda semana de seu primeiro trabalho, limpou metade de um servidor de build. Portanto, a tarefa básica é descobrir se existe um arquivo e, se houver, vamos excluí-lo. Mas existem algumas corredeiras traiçoeiras neste rio:

  • Tudo é um arquivo.

  • Os scripts têm poder real apenas se resolverem tarefas gerais

  • Para ser geral, usamos variáveis

  • Costumamos usar -f force em scripts para evitar intervenção manual

  • E também ame -r recursivo para garantir a criação, cópia e destruição em tempo hábil.

Considere o seguinte cenário:

Temos o arquivo que queremos excluir: filesexists.json

Este nome de arquivo é armazenado em uma variável

<host>:~/Documents/thisfolderexists filevariable="filesexists.json"

Também temos uma variável de caminho para tornar as coisas realmente flexíveis

<host>:~/Documents/thisfolderexists pathtofile=".."

<host>:~/Documents/thisfolderexists ls $pathtofile

filesexists.json  history20170728  SE-Data-API.pem  thisfolderexists

Então, vamos ver se -efaz o que deveria. Os arquivos existem?

<host>:~/Documents/thisfolderexists [ -e $pathtofile/$filevariable ]; echo $?

0

Faz. Magia.

No entanto, o que aconteceria, se a variável do arquivo fosse acidentalmente avaliada como nuffin '

<host>:~/Documents/thisfolderexists filevariable=""

<host>:~/Documents/thisfolderexists [ -e $pathtofile/$filevariable ]; echo $?

0

O que? É suposto retornar com um erro ... E este é o começo da história de como toda a pasta foi excluída por acidente

Uma alternativa poderia ser testar especificamente o que entendemos ser um 'arquivo'

<host>:~/Documents/thisfolderexists filevariable="filesexists.json"

<host>:~/Documents/thisfolderexists test -f $pathtofile/$filevariable; echo $?

0

Portanto, o arquivo existe ...

<host>:~/Documents/thisfolderexists filevariable=""

<host>:~/Documents/thisfolderexists test -f $pathtofile/$filevariable; echo $?

1

Portanto, este não é um arquivo e, talvez, não desejemos excluir esse diretório inteiro

man test tem o seguinte a dizer:

-b FILE

       FILE exists and is block special

-c FILE

       FILE exists and is character special

-d FILE

       FILE exists and is a directory

-e FILE

       FILE exists

-f FILE

       FILE exists and is a regular file

...

-h FILE

       FILE exists and is a symbolic link (same as -L)
Lefty G Balogh
fonte
4

Internamente, o comando rm deve testar a existência do arquivo de qualquer maneira,
então por que adicionar outro teste? Apenas emitir

rm filename

e desaparecerá depois disso, esteja lá ou não.
Use rm -f é que você não deseja nenhuma mensagem sobre arquivos inexistentes.

Se você precisar executar alguma ação se o arquivo NÃO existir, deverá testá-lo por conta própria. Com base no seu código de exemplo, este não é o caso nesta instância.

TG
fonte
1
Esta é realmente uma resposta bastante válida para o comando rm. Para outros comandos, sugiro que teste com -e.
21118 warhansen
Só que não é o que a pergunta faz.
Crayons
1
É muito o que a pergunta faz, se você ler a pergunta inteira, incluindo a parte "... e (se houver) ... a exclui".
TG
1

Se você estiver usando um NFS, "test" é uma solução melhor, porque você pode adicionar um tempo limite, caso o seu NFS esteja inoperante:

time timeout 3 test -f 
/nfs/my_nfs_is_currently_down
real    0m3.004s <<== timeout is taken into account
user    0m0.001s
sys     0m0.004s
echo $?
124   <= 124 means the timeout has been reached

Uma construção "[-e meu_arquivo]" será congelada até que o NFS esteja funcional novamente:

if [ -e /nfs/my_nfs_is_currently_down ]; then echo "ok" else echo "ko" ; fi

<no answer from the system, my session is "frozen">
FCA69
fonte
teste [são sinônimos. Você pode usar timeoutcom [tão bem, e testtambém congela se trava NFS.
esse outro cara