for d in ./*/ ; do (cd "$d" && somecommand); done
Estou tentando escrever um script que será executado em um determinado diretório com muitos subdiretórios de nível único. O script fará cd em cada um dos subdiretórios, executará um comando nos arquivos do diretório e fará o cd-out para continuar no próximo diretório. Qual é a melhor maneira de fazer isso?
A melhor maneira é não usar cd
:
find some/dir -type f -execdir somecommand {} \;
execdir
é como exec
, mas o diretório de trabalho é diferente:
-execdir command {} [;|+]
Like -exec, but the specified command is run from the
subdirectory containing the matched file, which is not normally
the directory in which you started find. This a much more
secure method for invoking commands, as it avoids race
conditions during resolution of the paths to the matched files.
Não é POSIX.
cd -P .
for dir in ./*/
do cd -P "$dir" ||continue
printf %s\n "$PWD" >&2
command && cd "$OLDPWD" ||
! break; done || ! cd - >&2
O comando acima não precisa fazer nenhum subshell - ele apenas rastreia seu progresso no shell atual, alternando $OLDPWD
e $PWD
. Quando você cd -
o shell troca o valor dessas duas variáveis, basicamente, conforme ele muda de diretório. Também imprime o nome de cada diretório enquanto ele trabalha lá para stderr.
Acabei de dar uma segunda olhada e decidi que poderia fazer um trabalho melhor com o tratamento de erros. Ele ignorará um dir no qual ele não pode cd
- e cd
imprimirá uma mensagem sobre o porquê de stderr - e será break
w / um código de saída diferente de zero se seu command
não for executado com êxito ou Se a execução de command
de alguma forma afetar sua capacidade de retornar ao diretório original - $OLDPWD
. Nesse caso, ele também executa cd -
last - e grava o nome do diretório de trabalho atual resultante em stderr.
pushd subdir
# do stuff
popd
pushd / popd são bash builtins que fornecem uma pilha de diretórios. Você pode fazer vários pushd
s e depois vários popd
s e voltar para onde começou. Você também pode manipular a pilha com dirs
.
Como um bash embutido, a documentação está no bash manpage ( man 1 bash
e pesquisa ( /
) para pushd, n
para avançar nos resultados da pesquisa) ou use help pushd
help popd
help dirs
.
for D in ./*; do
if [ -d "$D" ]; then
cd "$D"
run_something
cd ..
fi
done
Tags shell-script