Eu tenho uma hierarquia de arquivos como:
data
├── debug.log
├── messages
│ ├── msg001.txt
│ ├── msg002.txt
│ └── msg003.txt
└── pictures
├── msg002
│ └── pic001.jpg
└── msg003
├── pic001.jpg
└── pic002.jpg
Gostaria de encontrar todos os arquivos e todos os diretórios abaixo dos dois níveis superiores (dados, dados/mensagens e dados/imagens). Todas as coisas que não fazem parte da estrutura fixa da hierarquia, se isso faz sentido.
Posso fazer isso com uma única invocação de localização?
Posso encontrar os arquivos:
$ find data -type f | sort
data/debug.log
data/messages/msg001.txt
data/messages/msg002.txt
data/messages/msg003.txt
data/pictures/msg002/pic001.jpg
data/pictures/msg003/pic001.jpg
data/pictures/msg003/pic002.jpg
E posso encontrar os diretórios:
$ find data -mindepth 2 -type d | sort
data/pictures/msg002
data/pictures/msg003
Mas não posso combiná-los, porque -minprofundidade é uma opção, não um teste:
$ find data -type f -o \( -mindepth 2 -type d \) | sort
find: warning: you have specified the -mindepth option after a non-option argument -type, but options are not positional (-mindepth affects tests specified before it as well as those specified after it). Please specify options before other arguments.
data/messages/msg001.txt
data/messages/msg002.txt
data/messages/msg003.txt
data/pictures/msg002
data/pictures/msg002/pic001.jpg
data/pictures/msg003
data/pictures/msg003/pic001.jpg
data/pictures/msg003/pic002.jpg
(observe que data/debug.log não é encontrado aqui)
Existe alguma maneira de considerar a profundidade da hierarquia como um teste real?
O melhor erro que consigo pensar é usar um regexp no caminho para reconhecer os dois níveis principais de diretórios:
$ find data -type f -o \( -type d -regextype posix-extended \! -regex 'data(/[^/]+)?' \) | sort
Existe no FreeBSD find , também tem
-depth N
como condição:(e sim, isso pode ser facilmente confundido com a
-depth
opção.)Se você conhece o conjunto de diretórios que fazem parte da "estrutura fixa" (e na IMO você deveria, se a estrutura for realmente fixa), você pode simplesmente excluir aqueles:
ou o mesmo com grep:
(como você já está usando o formato de saída padrão
find
, em vez defind -print0
, seus nomes de arquivos provavelmente não contêm novas linhas)Esta não é a abordagem mais bonita, mas você poderia fazer algo como segue com o GNU
find
:find
com a-printf
flag irá imprimir os seguintes campos (separados pelo caractere nulo -\0
)Em seguida, o
awk
comando imprimirá os nomes de todos os arquivos ($2 == "f"
) e diretórios cuja profundidade seja igual ou superior a 2 ($2=="d" && $1 >= 2
).Observe que
-mindepth
é uma extensão não padrão (inicialmente do GNUfind
, mas posteriormente adicionada a algumas outras implementações). Ao contrário-maxdepth
, é fácil emular com predicados padrão. Por exemplo,LC_ALL=C find . -path './*/*'
emula ofind . -mindepth 2
.Então aqui:
(você não pode canalizar a saída para,
find
asort
menos que use registros delimitados por NUL, pois os caminhos de arquivo podem ser feitos de mais de uma linha.-print0
e-z
são extensões GNU,-print0
agora comuns (e em breve POSIX),-z
nem tanto).Isenção de responsabilidade: sou o atual autor do programa rawhide (rh) usado nesta resposta (no github/raforg).
Com rh , você pode fazer assim:
Isso pesquisa no
data
diretório arquivos (f
) e diretórios (d
) cuja profundidade seja pelo menos 2 (depth >= 2
).Funciona em Linux, FreeBSD, OpenBSD, NetBSD, macOS, Solaris e Cygwin.