Dir /AD no Powershell: onde ele foi parar?

Olá, hoje pela manhã me deparei com um problema bem comum: como listar os subdiretórios de um diretório? A princípio, parece bem simples. Quem está acostumado com o DOS e com o prompt de comando deve conhecer o comando DIR e o parâmetro /A dele, que permite listar somente os arquivos que tenham um atributo específico, que pode ser A (marca de arquivo), H (oculto), S (sistema), R (somente-leitura) e D (diretório). Logo, digitar dir /AD resolve nosso problema. No Windows Powershell, curiosamente, não existe essa opção, por vários motivos. No entanto, ele também permite realizar esta tarefa, com alguns parâmetros a mais. Basta usar o comando Get-ChildItem (também conhecido por dir ou ls) e redirecionar a saída para o cmdlet Where-Object, que filtra a saída dele: Get-ChildItem | where-object {$_.attibutes -band 16} ou ainda dir | where-object {$_.attibutes -band 16} ls | where {$_.attibutes -band 16} ls | ? {$_.attibutes -band 16} Todos fazem a mesma coisa, mas usando atalhos, que encurtam a digitação no console. O operador -band é um operador binário, que pega a propriedade attibutes (um mapa de bits, que especifica quais atributos estão presentes) e faz um E bit a bit com o número 16 (nesse caso, o AND bit a bit com o 16 serve para testar se o quinto bit está presente. Este quinto bit indica a flag de diretório). Ainda existe uma saída mais "antiquada" para o problema. Vamos pensar: se o comando DIR /AD resolve o problema e as ferramentas internas do Powershell são mais complicadas, vamos usar o DIR mesmo. A diferença é que podemos usar ele dentro do Powershell também: cmd /c dir /ad Note que usar o comando DIR dessa forma, por meio de um parâmetro do comando CMD, não retorna objetos do tipo arquivo, mas sim objetos tipo String, que nada mais são do que as linhas que o comando CMD retorna ao Powershell. Em resumo: você perde a orientação à objetos do Powershell. Outro detalhe importante: a primeira solução, usando o get-childitem com o where-object é a mais lenta de todas. Seria muito mais interessante utilizar um parâmetro do comando get-childitem, que melhoraria consideravelmente a performance. O problema é que eu não encontrei esse parâmetro ainda. Se quiser testar você mesmo, use o parâmetro -Recurse, que olha também nas subpastas, e veja o tempo que isso leva. Existe a possibilidade de criar uma função no Powershell que simula a digitação de comandos no CMD, mas esse é assunto para outro post... Até mais, Vinicius

Categorias dessa postagem: ,

Comentários

Anônimo : Consider changing
Get-ChildItem | where-object {$_.attibutes -band 16}

to
Get-ChildItem | where {$_.PSIsContainer}

Jeffrey Snover [MSFT]
Windows PowerShell/Aspen Architect
Visit the Windows PowerShell Team blog at: http://blogs.msdn.com/PowerShell
Visit the Windows PowerShell ScriptCenter at: http://www.microsoft.com/technet/scriptcenter/hubs/msh.mspx [5/1/07 13:52 - link]

Vinicius Canto : Obrigado Jeffrey!

Realmente o comando
Get-ChildItem | where {$_.PSIsContainer}
é mais rápido do que usar o -band. Fiz testes variados aqui e a média de ganho em performance quando trabalhando com o sistema de arquivos somente (não testei com o registro e outros providers) fica entre 30 e 33%.

Pra ficar mais rápido ainda, só se o comando Get-ChildItem tivesse um parâmetro específico para isso. Assim não teria o tempo extra para adicionar os NoteProperties nem o pipe.

Muito obrigado pelo comentário!


Vinicius [7/1/07 11:44 - link]