[ -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 ).