[ -e "$1/file.txt" ]
Em shells / [
implementations onde é suportado¹ retornará true se for possível fazer uma chamada de sistema stat()
no arquivo cujo caminho é a expansão de $1/file.txt
.
É equivalente a:
if ls -Ld -- "$1/file.txt" > /dev/null 2>&1
Pelo equivalente a:
if ls -d -- "$1/file.txt" > /dev/null 2>&1
isto é, se um lstat()
pode ser feito no arquivo, seria:
if [ -e "$1/file.txt" ] || [ -L "$1/file.txt" ]
para cobrir o caso de link simbólico "quebrado" (para o qual -e
retornaria falso, pois testa a existência após a resolução do link simbólico).
Agora, stat()
, lstat()
falha não significa necessariamente que o arquivo não existe, stat()
/ lstat()
pode falhar com outras condições de erro do que ENOENT (sem entrada) ENOTDIR (um componente de caminho não é um diretório). Pode ser que você não tenha acesso de pesquisa a nenhum componente do diretório, por exemplo.
Com a abordagem ls
, você pode remover o 2>&1
de ls
para informar o erro. Com [
, você não saberá a menos que use zsh
, em que pode usar $ERRNO
.
Se você não tiver acesso pesquisa ao diretório, talvez ainda tenha acesso read , para que ainda possa ler o conteúdo dos diretórios para ver se há um arquivo com esse nome.
Com zsh
, isso pode ser feito com ()(($#)) $1/file.txt(N)
, uma função anônima que retorna true se receber pelo menos um argumento ( ()(($#))
) para o qual passamos a lista de arquivos que correspondem à $1/file.txt(N)
glob, (N)
é ativar NULLGLOB
para essa glob.
Um problema separado com $1/file.txt
é o caso em que $1
é /
, caso em que isso se torna //file.txt
, o que em alguns sistemas não é igual a /file.txt
.
Portanto, com zsh
, para verificar se file.txt
existe como uma entrada no diretório $1
:
exists() {
local file="${1%/}/file.txt"
zmodload zsh/system
local ERRNO=0
[ -e "$file" ] || [ -L "$file" ] && return 0
case $errnos[ERRNO] in
(ENOENT|ENOTDIR) return 1;; # does not exist for sure
(*) ()(($#)) $file && return 0;;
esac
return 2 # meaning: don't know
}
Com outros shells, você pode tentar:
enoent_error=$(
LC_ALL=C ls -d /surely-does-not-exist 2>&1)
)
enoent_error=${enoent_error##*:}
enotdir_error=$(
LC_ALL=C ls -d /bin/sh/foo)
)
enotdir_error=${enotdir_error##*:}
exists() (
file=${1%/}/file.txt
if error=$(LC_ALL=C ls -d -- "$file" 2>&1 > /dev/null); then
return 0 # exists for sure
else
case $error in
(*:"$enoent_error"|*:"$enotdir_error")
return 1;; # does not exist for sure
esac
fi
return 2 # don't know
}
Isso pressupõe que ls
mensagens de erro na localidade C sigam o padrão *: fixed error message
, em que fixed error message
é diferente para cada condição de erro, mas sempre o mesmo para um determinado erro e não contém :
(em meu sistema somente ETOOMANYREFS
( Muitas referências: não pode emendar ) tem :
na mensagem de erro padrão da libc correspondente, mas isso não é um erro retornado por lstat()
, e de qualquer maneira não pode emendar não é encontrado em outras mensagens de erro).
¹ [
aka test
não suportava -e
inicialmente. ksh
introduziu -a
first (que então dobrou como um operador unário e binário), para acessível eu acredito (que de certa forma é mais correto), que foi posteriormente renomeado para -e
(embora a maioria das implementações ainda suporte -a
) e isso é -e
que o POSIX especifica para o utilitário padrão test
/ [
. /bin/sh
no Solaris 10 e mais antigo ainda é um Bourne shell não POSIX e seu [
incorporado ainda não suporta [ -e
nem [ -a
, então você precisaria recorrer a ls
ou chamar /bin/test
se você usasse esse shell (embora prefira usar um shell POSIX como /usr/xpg4/bin/sh
).