Você está reinventando find
.
Tente algo assim (usando o GNU findutils
e o GNU sort
):
find /target -iname '*.xyz' -printf '%hfind /target -iname '*.xyz' -printf '%h#!/bin/sh
for d in "$@" ; do
cd "$d"
echo "Match found in $d. Going to execute command"
# execute command
done
0' | sort -z -u |
xargs -0 -r /path/to/myscript.sh
0' | sort -z -u |
xargs -0 -r -I {} sh -c "cd {} ; yourcommandhere"
O -printf
imprime os nomes de diretório ( %h
) onde os arquivos '* .xyz' são encontrados, com bytes NUL ( sort
0
) como delimitador. xargs
é usado para eliminar duplicatas e, em seguida, cd
é usado para yourcommandhere
em cada diretório e executa printf
.
Você também pode escrever um script para ser executado com xargs. por exemplo,
find /target -iname '*.xyz' -exec bash -c \
'typeset -A seen
for f in "$@"; do
d="$(dirname "$f")";
if [[ ! -v $seen[$d] ]]; then
echo "Match found in $d. Going to execute command"
# Execute command
seen["$d"]=1
fi
done' {} +
exemplo simples de myscript.sh:
find /target -iname '*.xyz' -printf '%hfind /target -iname '*.xyz' -printf '%h#!/bin/sh
for d in "$@" ; do
cd "$d"
echo "Match found in $d. Going to execute command"
# execute command
done
0' | sort -z -u |
xargs -0 -r /path/to/myscript.sh
0' | sort -z -u |
xargs -0 -r -I {} sh -c "cd {} ; yourcommandhere"
Esta segunda versão será significativamente mais rápida se houver muitos diretórios correspondentes - ela só precisa bifurcar um shell uma vez (que, então, itera sobre cada argumento) em vez de bifurcar um shell uma vez por diretório.
BTW, nem sort
nem xargs
nem $seen[]
são realmente necessários aqui ... mas eles tornam muito mais fácil ler e entender o que está acontecendo. Tão importante quanto isso, eliminando as duplicatas antecipadamente (com o printf e o sort), ele é executado muito mais rápido do que usar apenas o bash e elimina o risco (razoavelmente mínimo) de executar o comando mais de uma vez em qualquer diretório.
Aqui está outra maneira de fazer a mesma coisa, sem ordenar ou xargs:
find /target -iname '*.xyz' -exec bash -c \
'typeset -A seen
for f in "$@"; do
d="$(dirname "$f")";
if [[ ! -v $seen[$d] ]]; then
echo "Match found in $d. Going to execute command"
# Execute command
seen["$d"]=1
fi
done' {} +
Isso usa uma matriz associativa no bash ( *.xml
) para acompanhar quais diretórios já foram vistos e processados. Observe que, se houver muitos milhares de arquivos -exec
correspondentes (o suficiente para exceder o comprimento máximo da linha de comando, para que o script bash seja bifurcado mais de uma vez), seu comando pode ser executado mais de uma vez em qualquer diretório.
O script executado pela opção %code% do find pode ser um script independente, como na versão xargs acima.
BTW, qualquer uma das variantes aqui poderia facilmente executar um script awk ou perl ou qualquer script em vez de um script sh ou bash.