Executar um comando em todas as subpastas

6

Se você tiver uma série de subpastas (como de a a z ) e quiser executar um comando em cada uma delas (como rm *.pdf ou ls *.pdf ), como você faz isso? A abordagem "manual" seria cd a , rm *.pdf ou ls *.pdf , cd .. , cd b , ... Isso parece muito complicado, então acredito que deve haver uma abordagem mais fácil.

    
por xyz 28.02.2013 / 21:03

8 respostas

7

Tente fazer isso (usando , expansão de cinta & globs):

rm -f {a..z}/*.pdf

ou

rm -f [a-z]/*.pdf

se o seu shell não tiver o recurso expansão de chave .

Ao contrário de [a-z] , {a..z} (também suportado por ksh93) não é glob , é expansão de contraventamento, é expandida (antes de globs ) independentemente de existir ou não arquivos. Isso é como rm -f a/*.pdf b/*.pdf ..., independentemente de a, b ... existir ou não. Observe também que, ao contrário de [a-z] , em que o intervalo pode ser localmente dependente (como pode incluir é, ś ...), {a..z} só funciona com intervalos de bytes (e de forma confiável somente nos intervalos de letras ASCII e intervalos de números )

(Merci Stephane Chazelas para explicações)

    
por 28.02.2013 / 21:14
2

Para esse exemplo específico:

rm [a-z]/*.pdf

Em qualquer shell.

No caso geral, com shells semelhantes a Bourne, você poderia colocar a lista de diretórios em $1 , $2 ... com:

set a b c foo bar...

e, em seguida, repeti-lo como:

for i do (cd -- "$i" && cmd -- *.pdf); done

Embora você possa fazer as duas coisas em apenas um comando:

for i in a b c foo bar...; do (cd -- "$i" && cmd -- *.pdf); done

O ponto é usar um subshell (...) para que cd afete apenas esse subcontexto.

    
por 28.02.2013 / 21:39
1

find pode ser a melhor solução, mas é facilmente possível no shell (bash):

GLOBIGNORE=.
for subdir in *; do
  test -d "$subdir" || continue
  cd "$subdir"
  ls *pdf
  cd -
done

ou ainda mais fácil

ls */*.pdf
    
por 28.02.2013 / 21:16
1

Use encontre . Algo como o seguinte iria encontrar todas as pastas (não mais do que duas pastas de profundidade) e, em seguida, executar rm <pathname>/*.pdf da pasta:

find pathwithsubfolders -type d -maxdepth 1 -mindepth 1 -exec rm {}/\*.pdf \;

Na minha opinião, a melhor coisa a fazer com comandos como esses (você sabe, aqueles com potenciais conseqüências terríveis) é prefixar uma declaração 'echo' na frente do comando que você está tentando executar ... apenas para fazer com certeza parece com o que você quer antes de você puxar o gatilho.

    
por 28.02.2013 / 21:07
0

Bem, supondo que você queira remover todos os arquivos PDF do diretório atual e todos os outros subdiretórios abaixo, você faria algo como

find -name "*.pdf" -exec rm -i {} \;

Duas coisas a serem observadas:

1- Eu adicionei a opção -i ao rm para que ele avise antes de remover qualquer arquivo, caso o find seja muito amplo no escopo.

2- É altamente recomendável que você leia a página find man. É facilmente um dos meus favoritos de todos os tempos.

    
por 28.02.2013 / 21:10
0

Se for apenas um nível de diretórios, você pode simplesmente fazer

rm */*.pdf

Isso apagará todos os arquivos pdf em todos os diretórios, mas nada mais.

Em um caso como este, você pode rever a lista de arquivos selecionados antes de fazer a exclusão. Para fazer isso, tente

ls */*.pdf

E se a lista for longa o suficiente para sair da tela, passe-a por um pager, por exemplo

ls */*.pdf | more
    
por 28.02.2013 / 21:16
0

Eu geralmente prefiro xargs:

find <path> -name '*.pdf' | xargs {ls|rm|etc}

Isso tem a vantagem de adicionar grep ou outras manipulações no meio do pipeline, mas tem a desvantagem de não lidar com arquivos que possuem espaços no arquivo ou no nome do caminho.

    
por 28.02.2013 / 21:19
0

Usando uma solução portátil (para usuários do Unix)

perl -e ''rm -rf "$_"/*.pdf' for "a" .. "z"'

Isso removerá os subdiretórios de forma recursiva em a..z dirs

    
por 28.02.2013 / 21:19