cd em todos os diretórios, execute o comando nos arquivos desse diretório e retorne ao diretório atual anterior


41

Estou tentando escrever um script que será executado em um determinado diretório com muitos subdiretórios de nível único. O script cdará em cada um dos subdiretórios, executará um comando nos arquivos no diretório e sairá para continuar no próximo diretório. Qual é a melhor maneira de fazer isso?


11
Dado o nível atual de informações fornecidas, não vejo relevância para youtube-dl.
— HalosGhost

Respostas:


83
for d in ./*/ ; do (cd "$d" && somecommand); done

12
Portanto, como o respondente omitiu qualquer tipo de explicação, tentarei uma. for d in ./*/inicia um loop que armazena todos os itens ./*/(uma lista de arquivos / pastas, neste caso) em uma variável $d. do (cd "$d" && somecommand);inicia o corpo do loop. Dentro do corpo, ele inicia um subshell e executa os comandos cde somecommand. Como é um shell filho, o shell pai (o shell do qual você está executando este comando) mantém seu CWD e outras variáveis ​​de ambiente. donesimplesmente fecha o corpo do loop.
— Qix

este método funciona para subdiretórios de diretórios:, for d in ./*/ ; do (cd "$d" && ls); donenão funcionará. mas for d in ./*/ ; do (cd "$d" && for d in ./*/ ; do (cd "$d" && ls); done ); donevai funcionar. -Usando ls como o comando neste exemplo.
— Michael Dimmitt

-bash: cd: ./*/: No such file or directory
— S. Tarık Çetin 26/10

15

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.


Isso funciona com aliases? Eu tenho um para baixar certos arquivos, mas ele não é reconhecido quando digito find * /. Link -type f -execdir md $ (cat .link) {} \;
— Something Jones

@AlgoJones não, findexecuta esses comandos, para que não tenha conhecimento de aliases. O que é mde é o .linkdiretório a?
— Muru

.link é um arquivo de texto com o URL que ele precisa baixar. md é um alias para o wget com um monte de sinalizadores definidos. Existe uma maneira de torná-lo consciente de aliases?
— Something Jones

@SomethingJones para seu uso caso particular, em bash: find . -type f -iname '*.link' -execdir ${BASH_ALIASES[md]} -i {} \;Você não precisa fazer catcom wgetque tem uma -ibandeira para a leitura em uma URL de um arquivo. Além disso, isso é um pouco diferente da sua pergunta original (já que você parece estar interessado apenas nos arquivos nomeados .linke não em outros arquivos que possam estar presentes).
— Muru

Você sabe como fazer isso com o zsh? Eu tentei o que você me deu e estou recebendo um erro de "Substituição incorreta". Além disso, como eu poderia extrair o conteúdo do arquivo .link? Sei que não preciso disso neste caso, mas imagino que precisarei em breve.
— Something Jones

2
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 subshells - apenas rastreia seu progresso no shell atual alternando $OLDPWDe $PWD. Quando cd -o shell troca o valor dessas duas variáveis, basicamente, à medida que altera os diretórios. Ele também imprime o nome de cada diretório, pois trabalha lá para stderr.

Acabei de dar uma segunda olhada e decidi que poderia fazer um trabalho melhor com o tratamento de erros. Irá pular um diretório no qual não pode cd- e cdimprimirá uma mensagem sobre o motivo de stderr - e exibirá breakum código de saída diferente de zero se o seu commandnão for executado com êxito ou se a execução commandafetar de alguma forma a capacidade de retornar ao diretório original - $OLDPWD. Nesse caso, ele também faz uma cd -última - e grava o nome do diretório de trabalho atual resultante no stderr.


1
for D in ./*; do
    if [ -d "$D" ]; then
        cd "$D"
        run_something
        cd ..
    fi
done
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.