
Como eu listaria todos os diretórios que fazemnãotem um arquivo com um determinado nome de arquivo dentro? por exemplo, dada esta árvore
/
/a
README
file001
file002
/b
README
file001
/c
file003
Quero listar os diretórios que fazemnãotem um arquivo chamado README
, neste caso seria directory /c
. Como eu faria isso? Não consigo pensar em nenhuma sintaxe usando, por exemplo find
.
Responder1
Assumindo uma find
implementação como GNU find
que aceita um {}
argumento incorporado para -exec
:
$ find . -type d \! -exec test -e '{}/README' \; -print
ou, sem a incorporação problemática:
$ find . -type d ! -exec sh -c 'test -e "$1"/README' sh {} \; -print
Exemplo
Aqui os diretórios 1/1 a 5/5 possuem um README, os outros diretórios estão vazios.
$ tree
.
|-- 1
| `-- 1
| `-- README
|-- 10
| `-- 10
|-- 2
| `-- 2
| `-- README
|-- 3
| `-- 3
| `-- README
|-- 4
| `-- 4
| `-- README
|-- 5
| `-- 5
| `-- README
|-- 6
| `-- 6
|-- 7
| `-- 7
|-- 8
| `-- 8
`-- 9
`-- 9
Agora, quando executamos esta versão do nosso find
comando:
$ find . -type d \! -exec test -e '{}/README' \; -print
.
./10
./10/10
./7
./7/7
./9
./9/9
./6
./6/6
./5
./8
./8/8
./4
./1
./3
./2
Referências
Responder2
Não há necessidade de find
. Basta usar o shell:
for d in */; do [ -f "$d"README ] || printf '%s\n' "$d"; done
c/
Se precisar que seja recursivo, você pode usar (for bash
, zsh
pode fazer isso por padrão, use set -o globstar
in ksh93
):
shopt -s globstar
for d in **/; do [ -f "$d"README ] || printf '%s\n' "$d"; done
(observe que os arquivos de ponto são excluídos por padrão).
Responder3
Você pode usar a -exec
opção de find
verificar o arquivo e, em seguida, imprimir todos os resultados cuja verificação falhou.
find /path/to/base -mindepth 1 -maxdepth 1 -type d -exec test -e {}/README \; -o -print
Responder4
Portavelmente, você poderia fazer:
find . -type d -exec sh -c '
for dir do
[ -f "$dir/README" ] || printf "%s\n" "$dir"
done' sh '{}' +
[ -f file ]
testa se o arquivoexiste eé confirmado como um arquivo normal (após resolução do link simbólico).
Se você quisesse testar se ele existe apenas (como uma entrada nesse diretório), independentemente do seu tipo, você precisaria: [ -e file ] || [ -L file ]
, mas observe que você precisa de permissão de pesquisa no diretório para realizar esses testes. Você pode querer adicionar alguns [ -x "$dir" ]
testes para dar conta de casos como:
find . -type d -exec sh -c '
for dir do
if [ -x "$dir" ]; then
[ -f "$dir/README" ] || printf "%s\n" "$dir"
else
printf >&2 "Cannot tell for \"%s\"\n" "$dir"
fi
done' sh '{}' +
Ou para evitar a condição de corrida, com zsh
:
find . -type d -exec zsh -c '
zmodload zsh/system
for dir do
ERRNO=0
if [ ! -f "$dir/README" ]; then
if [ "$errnos[ERRNO]" = ENOENT ]; then
printf "%s\n" "$dir"
else
syserror -p "ERROR: $dir/README: "
fi
fi
done' zsh '{}' +
Veja tambémComo posso saber se um arquivo normal não existe no Bash?em SO.