AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • Início
  • system&network
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • Início
  • system&network
    • Recentes
    • Highest score
    • tags
  • Ubuntu
    • Recentes
    • Highest score
    • tags
  • Unix
    • Recentes
    • tags
  • DBA
    • Recentes
    • tags
  • Computer
    • Recentes
    • tags
  • Coding
    • Recentes
    • tags
Início / computer / Perguntas / 1863934
Accepted
dargaud
dargaud
Asked: 2024-12-07 02:12:43 +0800 CST2024-12-07 02:12:43 +0800 CST 2024-12-07 02:12:43 +0800 CST

Excluir diretórios contendo apenas arquivos .directory

  • 772

Fiz muita limpeza removendo arquivos em uma árvore de diretórios. Agora, gostaria de excluir os diretórios vazios, pois agora há muitos diretórios 'quase vazios': eles contêm apenas um .directoryarquivo oculto. Então, fazer find -emptyaparece... vazio. Não quero excluir os arquivos de ponto dos diretórios que contêm outros arquivos.

Posso pensar em algum script bash complexo encadeado find, mas não consigo pensar em uma maneira simples de fazê-lo... Por exemplo, a solução aqui ( Linux: excluir todos os diretórios com apenas um arquivo e nenhum subdiretório ) não encontra arquivos dot.

Esclarecimento : A .directoryé um arquivo de texto oculto criado pelo KDE ( dolphin?) e contém informações sobre como exibir o conteúdo do diretório, por exemplo, miniaturas, ou lista de arquivos, ou apenas seus ícones, etc. Quando os arquivos são excluídos, o .directoryarquivo permanece, mas agora é praticamente inútil.

linux
  • 3 3 respostas
  • 284 Views

3 respostas

  • Voted
  1. Kamil Maciorowski
    2024-12-07T08:11:37+08:002024-12-07T08:11:37+08:00

    Você mencionou find -empty, então seu findprovavelmente é GNU find. Nesta resposta, usarei vários recursos não portáteis do GNU find.

    Por favor, teste minha solução em um diretório expensable primeiro. A solução é:

    find . -type d \( -empty -delete -o -exec sh -c '
       special=".directory"
       test -f "$1/$special" \
       && find "$1" -mindepth 1 -maxdepth 1 ! -name "$special" | { ! grep -q .; } \
       && rm "$1/$special"
    ' find-sh {} \; -delete \) -print
    

    Funciona assim:

    • Porque -deleteimplica -depth, o comando processará um diretório somente após processar tudo nele. Isso é bom, pois queremos que ele processe e possivelmente exclua subdiretórios mais profundos primeiro, então quando ele chegar a um pai, há uma chance de que ele tenha ficado vazio ou quase vazio.

    • O comando atua em arquivos do tipo diretório ( -type d).

    • Se o diretório atualmente considerado estiver vazio, o comando tenta excluí-lo ( -empty -delete).

    • Caso contrário (ou seja, se o diretório não estiver vazio), um trecho de código shell é executado. Francamente, ele será executado também se o diretório estiver vazio e a exclusão falhar; mas, neste caso, o trecho deve ser inofensivo, então está tudo bem.

      O código shell usa &&, então cada próximo passo é executado se e somente se seu passo precedente for bem-sucedido. Os passos são:

      • Teste se há um arquivo regular com nosso nome "especial" lá ( test -f …).
      • Comece a encontrar arquivos diretamente no diretório ( -mindepth 1 -maxdepth 1) com nomes diferentes do nome "especial". Se a saída do inner findestiver vazia, então grep -q .sairá com status de saída diferente de zero, então ! grep …nos dará um sucesso…
      • E então rmserá executado para remover o arquivo "especial".

      Somente se isso rmfor bem-sucedido, o -execteste será considerado verdadeiro para o diretório e o último -deleteserá tentado.

    • -printimprimirá os nomes dos caminhos dos diretórios para os quais -delete(o primeiro ou o segundo) foram bem-sucedidos.

    Notas:

    • Nos meus testes -deletenão apagou .nem quando estava vazio, embora tenha conseguido formalmente.
    • -namepega um padrão. Em geral, se o nome "especial" contiver *, ?ou [então você precisa ajustar o código. .directoryé seguro nesse assunto.
    • 5
  2. Best Answer
    Peter Cordes
    2024-12-07T12:48:42+08:002024-12-07T12:48:42+08:00

    Dada a complexidade de algumas das respostas, eu diria que Perl ou Python são as ferramentas certas para percorrer uma árvore de diretórios, obter uma lista de entradas de diretório e verificar se ela é exatamente igual a uma lista de 1 elemento contendo .directory(e se é um arquivo regular).

    Ter findum comando complexo fork/exec sh -cpara cada subdiretório parece um desperdício, e meus olhos estão vidrados tentando seguir a lógica na resposta de Kamil. Supondo que uma listagem de diretório recursiva de toda a árvore caberá facilmente na RAM do seu sistema, ferramentas simples são o caminho a seguir.

    Perl temFile::Find que recursivamente depth-first, o que é bom, mas ele quer chamar sua função de retorno de chamada em cada entrada de diretório. Então, se você quisesse uma listagem de diretório, você teria que fazer isso sozinho em cima disso. Não é um showstopper, mas não é o ideal, então eu olhei para Python.

    A função de biblioteca padrão do Python directory walk é os.walk, que é a respiração primeiro. Mas, curiosamente, ela produz um iterador de root, dirs, files( exemplo de uso que copiei ), onde os dois últimos são listas do conteúdo do diretório root, divididos em arquivos de diretório e não diretório. É exatamente isso que queremos; ou seria em uma busca em profundidade primeiro.

    Para seu caso de uso, provavelmente não há problema em remover o .directoryarquivo em um diretório contendo apenas outros diretórios? Se sim, podemos fazer isso com Python, então use find -depth -type d -empty -delete (ou -print -deletepara ver quais diretórios mataremos).

    #!/usr/bin/python
    
    import os
    import sys
    
    if (len(sys.argv) != 2):
        print ("usage: dir-remove path")
        exit(1)       # not really needed; sys[1] errors on its own if there aren't enough args, and I haven't implemented looping over multiple args.  But make sure 
    
    for root, dirs, files in os.walk(sys.argv[1]):
        print (root, dirs, files)
        if (files == [".directory"]):
            # only one non-directory file and it's called .directory
            print("os.unlink " + os.path.join(root, ".directory") )       # debug
            #os.unlink (os.path.join(root, ".directory") )                  # for real
    

    Configuração de teste:

    $ mkdir -p foo/bar/baz
    $ touch foo/bar/baz/.directory  foo/bar/.directory  foo/{a.txt,.directory}
    $ find foo -exec ls -dn {} +
    drwxr-xr-x 3 1000 1000 100 Dec  7 00:35 foo
    -rw-r--r-- 1 1000 1000   0 Dec  7 00:05 foo/a.txt
    drwxr-xr-x 3 1000 1000  80 Dec  7 00:35 foo/bar
    drwxr-xr-x 2 1000 1000  60 Dec  7 00:35 foo/bar/baz
    -rw-r--r-- 1 1000 1000   0 Dec  7 00:35 foo/bar/baz/.directory
    -rw-r--r-- 1 1000 1000   0 Dec  7 00:35 foo/bar/.directory
    -rw-r--r-- 1 1000 1000   0 Dec  7 00:05 foo/.directory
    

    uso, versão de depuração-impressão:

    ./dir-remove.py /tmp/foo
    /tmp/foo ['bar'] ['a.txt', '.directory']
    /tmp/foo/bar ['baz'] ['.directory']
    os.unlink /tmp/foo/bar/.directory
    /tmp/foo/bar/baz [] ['.directory']
    os.unlink /tmp/foo/bar/baz/.directory
    

    Uso, para valer: execute o script Python para remover .directoryarquivos, depois find ... -deletepara remover diretórios vazios depth-first. Eu poderia ter tido Python exec finddepois do loop se quisesse construir uma solução mais reutilizável.

    $ ./dir-remove.py foo   # with both prints commented, os.unlink uncommented
    $ find foo
    foo/a.txt
    foo/.directory
    foo/bar
    foo/bar/baz
    
    $ find foo -depth -type d -empty -print -delete
    foo/bar/baz
    foo/bar
    

    Tudo o que resta é foo/a.txte foo/.directory(e o diretório fooem si, é claro).

    Limitação: foo/bar/.directoryteria sido removido mesmo se foo/bar/baznão estivesse vazio e não acabou sendo removido. Não vejo uma solução trivial para isso sem fazer minha própria busca em profundidade em Python, ou voltar para Perl e usar its File::Finde fazer uma listagem de diretórios eu mesmo.

    Eu só sei um pouco de Python, mas mesmo assim foi muito fácil fazer isso, e estou contando com bibliotecas padrão para o trabalho pesado, então espero que seja robusto.

    • 3
  3. tink
    2024-12-07T06:36:15+08:002024-12-07T06:36:15+08:00

    Não tenho certeza se entendi completamente o que você está dizendo, mas isso faz o que você está perguntando?

    $ find tmp
    tmp/
    tmp/a
    tmp/1
    tmp/1/2
    tmp/1/2/.directory
    tmp/1/2/c
    tmp/1/2/3
    tmp/1/2/3/.directory
    tmp/1/2/3/d
    tmp/1/b
    

    Então execute:

    $ find -depth -empty -name .directory -exec rm -vrf {} \;
    removed directory './tmp/1/2/.directory'
    removed directory './tmp/1/2/3/.directory'
    

    O que então produzirá:

    $ find tmp/
    tmp/
    tmp/a
    tmp/1
    tmp/1/2
    tmp/1/2/c
    tmp/1/2/3
    tmp/1/2/3/d
    tmp/1/b
    
    • 0

relate perguntas

  • Como eu faria minha máquina Linux parecer que está executando o Windows?

  • Existe um equivalente a cd - para cp ou mv?

  • execute o contêiner do docker como root

  • Como ativar o sensor de impressão digital no domínio e no diretório ativo do Linux

  • Como alterar permanentemente Ctrl + C para Ctrl + K no CentOS 7?

Sidebar

Stats

  • Perguntas 205573
  • respostas 270741
  • best respostas 135370
  • utilizador 68524
  • Highest score
  • respostas
  • Marko Smith

    Como posso reduzir o consumo do processo `vmmem`?

    • 11 respostas
  • Marko Smith

    Baixar vídeo do Microsoft Stream

    • 4 respostas
  • Marko Smith

    O Google Chrome DevTools falhou ao analisar o SourceMap: chrome-extension

    • 6 respostas
  • Marko Smith

    O visualizador de fotos do Windows não pode ser executado porque não há memória suficiente?

    • 5 respostas
  • Marko Smith

    Como faço para ativar o WindowsXP agora que o suporte acabou?

    • 6 respostas
  • Marko Smith

    Área de trabalho remota congelando intermitentemente

    • 7 respostas
  • Marko Smith

    O que significa ter uma máscara de sub-rede /32?

    • 6 respostas
  • Marko Smith

    Ponteiro do mouse movendo-se nas teclas de seta pressionadas no Windows?

    • 1 respostas
  • Marko Smith

    O VirtualBox falha ao iniciar com VERR_NEM_VM_CREATE_FAILED

    • 8 respostas
  • Marko Smith

    Os aplicativos não aparecem nas configurações de privacidade da câmera e do microfone no MacBook

    • 5 respostas
  • Martin Hope
    Vickel O Firefox não permite mais colar no WhatsApp web? 2023-08-18 05:04:35 +0800 CST
  • Martin Hope
    Saaru Lindestøkke Por que os arquivos tar.xz são 15x menores ao usar a biblioteca tar do Python em comparação com o tar do macOS? 2021-03-14 09:37:48 +0800 CST
  • Martin Hope
    CiaranWelsh Como posso reduzir o consumo do processo `vmmem`? 2020-06-10 02:06:58 +0800 CST
  • Martin Hope
    Jim Pesquisa do Windows 10 não está carregando, mostrando janela em branco 2020-02-06 03:28:26 +0800 CST
  • Martin Hope
    andre_ss6 Área de trabalho remota congelando intermitentemente 2019-09-11 12:56:40 +0800 CST
  • Martin Hope
    Riley Carney Por que colocar um ponto após o URL remove as informações de login? 2019-08-06 10:59:24 +0800 CST
  • Martin Hope
    zdimension Ponteiro do mouse movendo-se nas teclas de seta pressionadas no Windows? 2019-08-04 06:39:57 +0800 CST
  • Martin Hope
    jonsca Todos os meus complementos do Firefox foram desativados repentinamente, como posso reativá-los? 2019-05-04 17:58:52 +0800 CST
  • Martin Hope
    MCK É possível criar um código QR usando texto? 2019-04-02 06:32:14 +0800 CST
  • Martin Hope
    SoniEx2 Altere o nome da ramificação padrão do git init 2019-04-01 06:16:56 +0800 CST

Hot tag

windows-10 linux windows microsoft-excel networking ubuntu worksheet-function bash command-line hard-drive

Explore

  • Início
  • Perguntas
    • Recentes
    • Highest score
  • tag
  • help

Footer

AskOverflow.Dev

About Us

  • About Us
  • Contact Us

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve