No PowerShell, eu poderia executar algo assim em uma única linha
Get-ChildItem | foreach {
if ($_ -match '.+?\.py$' -eq $true) {
$_ | Do-Thing -WithFile
}
if ($_ -match '.+?\.pdf$' -eq $true) {
$_ | Do-Thing -WithOtherFile
}
}
igual a
Get-ChildItem | foreach { if ($_ -match '.+?\.py$' -eq $true) { $_ | Do-Thing -WithFile } if ($_ -match '.+?\.pdf$' -eq $true) { $_ | Do-Thing -WithOtherFile } }
A funcionalidade específica disso que eu aprecio é poder fazer referência ao objeto de pipeline via $_
para ser usado no próximo comando e ser capaz de executar execução condicional com base em partes divididas de saída via | foreach {}
.
Eu sei que no bash seria fácil receber vários padrões de uma só vez via
> ls | egrep '\.py$|\.pdf$'
some_foo.py
some_bar.py
foo.pdf
bar.pdf
É possível estender isso em um liner com o que está disponível por padrão, onde eu seria capaz de fazer o equivalente a
| foreach { if ($_ -match '.+?\.py$') {Do-Thing -With $_ } if (...) { Do-Thing -WithOther $_ } }
ou o Bash redireciona apenas o stdout de um comando para o stdin de outro? Acho muitos usos diversos para essa dinâmica no PowerShell, mas não ouvi falar de um equivalente no Bash.
Não é nada que bloquear e escrever um script na sintaxe usual funcione bem, fiquei curioso porque é incrivelmente útil no PS.
Procurando por: $_ , | foreach {}
equivalentes onde eu poderia dividir a saída, verificar as condições e, em seguida, ser capaz de referenciar a parte da saída dividida por algum nome. No caso dos PSs, $ _
Eu sei que existem muitas maneiras pelas quais o PS é fundamentalmente diferente do Bash, então eu não ficaria surpreso se isso fosse específico do PS.
Para um melhor contexto, veja um exemplo no PS, onde você pesquisaria recursivamente arquivos com extensões python e pdf e faria um registro deles em seus respectivos arquivos de texto
Get-ChildItem -Recurse | foreach {
if ($_ -match '.+?\.py$' -eq $true) {
$_ | Out-File -encoding utf8 -Append py_list.txt
}
if ($_ -match '.+?\.pdf$' -eq $true) {
$_ | Out-File -encoding utf8 -Append pdf_list.txt
}
}
fonte
find
é a "Ferramenta certa para o trabalho", quando o trabalho é definido como "faça algo com vários arquivos, possivelmente correspondendo a um padrão, recorrendo a subdiretórios". Se você quisesse, por exemplo, torcer pelos scripts Python e vaiar nos PDFs, por exemplo, você poderia.find . -name '*.py' -exec echo 'Yay, {}!' \; -o -name '*.pdf' -exec echo 'Boo, {}!' \;
Isso não depende de nenhum recurso especial que apenas o GNUfind
possui (portanto, ele funcionará imediatamente no macOS, por exemplo).Respostas:
Sim (quase) e não. O Bash não suporta 'objetos' de pipelining em primeiro lugar - seus pipelines, mesmo internos, ainda são construídos em subprocessos e stdio comum (que é um bytestream) e, portanto, você só pode interagir com linhas de texto comuns (por exemplo, uma linha lista por caminhos de arquivos), não objetos complexos.
Então, o equivalente mais próximo seria
while read -r <var>; do ...; done
. Mais sobre isso mais tarde.Sua tarefa específica pode ser melhor gerenciada usando um
for <var> in <words>
loop simples com curingas :Você nem precisa reproduzir as verificações explícitas - você pode ter dois loops:
Para fazer o mesmo recursivamente , você pode a) usar os curingas recursivos de Bash:
ou b) use
find
e faça um loop sobre cada linha em stdin :(Sim, eu deveria ter usado
IFS="" read -r <var>
nomes de arquivos que terminam com um espaço - mas, felizmente, não tenho nenhum no meu sistema para não incomodar.)Mais uma vez, você pode pular as verificações manuais de nome de arquivo e solicitar o que precisa com antecedência.
Variante b:
O mesmo, mas usando a opção find 's -exec:
fonte
*.yyy
(possivelmente descendo em subdiretórios) em um script de shell do Bash?";)