Você não pode usar grupos de captura do regexp no comando para executar. Se você usar find -regex
para restringir as correspondências, você terá que fazer alguma correspondência extra no comando. Você pode fazer isso invocando um shell e usando suas próprias construções de correspondência de padrões. Por exemplo, se foo
e bar
forem sequências constantes e regex1
não corresponder a bar
:
find … -exec sh -c '
x=${0#foo}
y=${x#*bar}
x=${x%%bar*}
something "$x" "$y"
' {} \;
Invocar um shell tem uma pequena sobrecarga. Você pode melhorar um pouco o desempenho invocando o shell em lotes.
find … -exec sh -c '
for item do
item=${item#foo}
y=${item#*bar}
x=${item%%bar*}
something "$x" "$y"
done
' sh {} +
Como você já fez alguma filtragem, talvez consiga fugir dos padrões de shell que correspondem a mais de regex1
e regex2
, mas, para os caminhos desse formulário específico, correspondem à mesma peça. Se foo
e bar
não puderem ser expressos com padrões de shell comuns, você poderá invocar ksh ou bash, que suportam padrões extras que são tão poderosos quanto expressões regulares: @(alter|native)
, *(zero-or-more)
, +(one-or-more)
, ?(optional)
e !(negated)
. No bash , esses padrões precisam ser ativados com shopt -s extglob
. Em ksh, eles estão disponíveis nativamente.
No bash, há uma construção de correspondência de expressão regular que você pode usar em condicionais : [[ $STRING =~ REGEXP ]]
. O regexp é um ERE (como find -regextype posix-egrep
). (O Zsh tem um semelhante; o ksh tem =~
, mas não expõe os grupos de captura.) Os grupos de captura estão disponíveis por meio do array BASH_REMATCH
.
find … -exec bash -c '
for item do
[[ item =~ foo(regex1)bar(regex2) ]]
something "${BASH_REMATCH[1]}" "${BASH_REMATCH[2]}"
done
' bash {} +
Uma abordagem alternativa é imprimir o resultado e filtre-o , depois chame xargs
para invocar o programa. Organize para ter o primeiro e o segundo argumento como itens sucessivos e execute xargs -n 2
. Use bytes nulos como separadores para evitar o formato de cotação estranho de xargs ou use -d '\n'
para usar a análise linha por linha estrita. Ferramentas GNU recentes, como sed, podem trabalhar com bytes nulos em vez de novas linhas para separar registros.
find … -print0 |
sed -z 's/^foo\(regex1\)bar\(regex2\)$/\x00/'
| xargs -n2 -0 something
Uma abordagem alternativa é eliminar e usar o recurso de globalização recursiva de ksh93, bash ou zsh: **/
corresponde a subdiretórios recursivamente. Isso não é possível para expressões de localização complexas envolvendo conectores booleanos, mas é o suficiente para a maioria dos casos. Por exemplo, no bash (observe que isso recorre a links simbólicos para diretórios, como find -L
):
shopt -s extglob globstar
for x in **/*bar*; do
if [[ item =~ foo(regex1)bar(regex2) ]]; then
something "${BASH_REMATCH[1]}" "${BASH_REMATCH[2]}"
fi
done
No zsh:
for x in **/*bar*; do
if [[ item =~ foo(regex1)bar(regex2) ]]; then
something $match[1] $match[2]
fi
done