Este é zmv
um comando para substituir de forma não recursiva qualquer número de espaços por um único sublinhado (graças a Stéphane Chazelas, que me ajudou com isso):
zmv -- '* *' '${f// ##/_}'
E aqui está um comando da internet, que parece fazer a mesma coisa, mas de forma recursiva:
zmv -- '(**/)(* *)' '$1${2//( #-## #| ##)/_}'
Alguém poderia explicar como funciona? Especificamente, como ( #-## #| ##)
funciona a peça?
Existem duas diferenças:
some directory/some file
→some directory/some_file
).foo bar
,foo - bar
,foo ---bar
todos mapeiam parafoo_bar
.foo-bar qux
mapeia parafoo_bar_qux
.foo-bar
também seria mapeado parafoo_bar
, mas não corresponde ao padrão.No segundo comando,
(**/)(* *)
corresponde a todos os caminhos no diretório atual onde o nome base do arquivo contém pelo menos um espaço. Os parênteses criam grupos nomeados, quezmv
são colocados nos parâmetros posicionais, de forma que a parte do diretório (equivalente a$f:h/
) esteja disponível como$1
no texto de substituição e o nome base (equivalente a$f:t
) esteja disponível como$2
. Observe que o(**/)
grupo é uma exceção: normalmente os parênteses desativam o comportamento recursivo do**
, maszmv
tratam(**/)
de forma especial.Na substituição,
$1$2
seria o nome original (o final/
faz parte de$1
).${2//…/_}
substitui cada ocorrência do padrão… por um sublinhado. O padrão( #-## #| ##)
usa o operador “ou”: uma correspondência é uma correspondência de#-## #
(zero ou mais espaços, um ou mais traços, zero ou mais espaços) ou uma correspondência de##
(um ou mais espaços).