Verifique se existe um determinado arquivo em um diretório

2

Oi eu estou tentando fazer um if que obtém um caminho para um diretório como um argumento e verifica se file.txt está no diretório. E retorna 1 se for, 0 caso contrário.

     if [ -e $1/file.txt ]; then
         exit 1
     else exit 0
     fi

Também eu tentei o método ls

     ls $1/file.txt && exit 1 || exit 0

Existe algum outro método? Ou eu estou perdendo alguma coisa?

    
por Dendarwx 24.11.2016 / 18:39

2 respostas

2

Para verificar se um arquivo file.txt está presente no diretório passado como o primeiro argumento para o script ou função, use

[ -e "$1/file.txt" ]

Não esqueça de aspas duplas de substituição .

Isso será bem-sucedido se o arquivo existir e falhar se o arquivo não existir. Falha inclui o caso em que o arquivo existe, mas não pode ser alcançado, por exemplo porque você não tem permissão para percorrer o diretório.

Observe que, em scripts de shell, e quando se trata de processar status de saída, 0 significa sucesso e 1 (ou mais, até 125) significa falha. Consulte Que retorno / valores de saída podem ser usados em funções / scripts bash? e Código de saída padrão quando o processo é encerrado? para mais detalhes. Portanto, se você quiser verificar se existe um arquivo, seu script ou função deve retornar 0 se o arquivo existir e 1 caso contrário. Seu snippet faz o contrário: verifica se o arquivo não existe.

 if [ -e "$1/file.txt" ]; then
    exit 0
 else
    exit 1
 fi

é apenas uma maneira mais complicada de escrever

[ -e "$1/file.txt" ]
exit

( exit sem argumento de status usa o status do comando executado anteriormente). E se isso estiver no final do script, então exit é redundante.

Se você quiser verificar se o arquivo não existe, inverta o comando com o operador ! shell:

! [ -e "$1/file.txt" ]

ou o operador ! test / [ :

[ ! -e "$1/file.txt" ]
    
por 25.11.2016 / 01:37
0
[ -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 ).

    
por 12.12.2017 / 10:45