Função recursiva não funciona

3

Eu sei que esta é uma idéia ridícula, mas estou tentando fazer com que um script funcione e se ramifique em todos os diretórios do sistema de arquivos. O nome do arquivo é "Everywhere.sh". Aqui está o código:

#!/bin/bash

recurse(){
    cd $1   
    for INDEX in $(echo *)
    do
        recurse $INDEX
    done
}

recurse /

Como eu posso mudar isso (exceto su raiz -c "./Everywhere.sh") para que funcione corretamente?

EDIT: Eu só preciso disso corrigido; Eu não preciso de um método diferente para execução.

    
por Mr. Minty Fresh 13.01.2016 / 21:38

3 respostas

7

(Sua pergunta parece ter sido respondida como já foi dito; quero abordar um aspecto diferente dela.)

Mesmo que você tenha dito "Eu sei que isso é ridículo", apenas mencionarei que executar algum comando em cada diretório em um sistema de arquivos pode ser feito em uma única linha com:

find / -type d -exec sh -c 'cd "$1" && some_command' sh {} \;

Isso não vai lidar com o problema de permissões, mas é muito mais simples do que escrever uma função de shell recursiva.

    
por 14.01.2016 / 05:27
2

Um dos principais problemas com o script original foi que ele mudou para os diretórios, mas nunca voltou atrás deles.

recurse ()
(
  recurse2 ()
  {
    [ $_recurse_stop -eq 1 ] && return
    cd "./$1" || return
    pwd ## do whatever you want in the pwd
    for entry in * .*;
    do
        [ "." = "$entry" -o ".." = "$entry" ] && continue;
        [ -d "$entry" -a ! -h "$entry" ] && recurse2 "$entry";
    done
    cd ..
  }

  _recurse_stop=0
  trap '_recurse_stop=1' 2
  recurse2 "$1"
)

Outra mudança foi substituir $(echo *) pelo simples * glob.

Eu também fiz a correção simples de tentar apenas recuperar diretórios (o -d test).

Depois de vários comentários perspicazes de @Wildcard e @mikeserv, este script agora:

  • cria um subnível de nível superior para isolar todos os cd ing,
  • se recusa a cd nos diretórios de links simbólicos ( ! -h ) e
  • configura um trap para interromper a recursão (por meio de uma variável de sinal) se receber um sinal de ^ C (interrupção)
por 14.01.2016 / 19:22
-1

O exemplo simples:

cdtree()
    if    OLDPWD=${1-.} cd -P - &&
          set . ./.[!.]*/ ./..?*/ ./*/ "" "${1%"${1#.}"}."
    then  while [ "${1:+1}" ]   && shift
          do    [ ! -d "$1" -o  -h "${1%/}" ]|| cdtree "$1"
          done; cd  -P "$2"
    else  printf %s\n "$PWD/${1#./}"
    fi

Ele lida com . diretórios nomeados com um ponto inicial, ele se recusa a seguir links simbólicos e faz uma tentativa razoável de restaurar o diretório de trabalho atual do shell para aquele em que foi lançado.

Ele ignora todos, exceto seu primeiro argumento, ou então, se chamado sem argumentos, recursiva a árvore com raiz em . .

É capaz:

{    find / -type d | wc -l
     cdtree /       | wc -l
}    2>/dev/null
23928
23928

E bastante rápido. find percorre minha árvore raiz em aproximadamente 0,6 segundos. cdtree() in dash faz isso em 1,6 segundos. Isso é basicamente o mesmo tempo de conclusão da versão anterior. Com a versão antiga o tempo de execução de bash era excruciante - algo como 20 vezes o de dash . Com esta edição é apenas menos de 5 segundos, e assim é tolerável, mas ainda é um cão. Eu realmente não entendo a popularidade de bash .

O exemplo prático:

cdtree()
    if    OLDPWD=${1-.} cd -P - &&
          "${cd_tree_callback-:}" "$PWD" &&
          set . ./.[!.]*/ ./..?*/ ./*/ "" "${1%"${1#.}"}."
    then  while [ "${1:+1}" ]   && shift
          do    [ ! -d "$1" -o  -h "${1%/}" ]|| cdtree "$1"
          done; cd  -P "$2"
    else  printf %s\n "$PWD/${1#./}"
    fi

Porque a única razão pela qual eu posso pensar que alguém poderia querer fazer tal coisa no atual processo do shell é afetar o estado atual do shell de alguma forma ou então executar algum comando específico por diretório atual - esse exemplo faz é realmente possível.

Se $cd_tree_callback estiver definido com o nome de algum comando, ele será executado para cada diretório em que cd_tree possa ser alterado diretamente. Se o diretório de trabalho atual for alterado como resultado, o resultado acima pode ser estranho - mas isso é apenas um aviso e você deve fazer o que quiser. Caso contrário, se for não definido , o retorno de chamada será um comando não operacional, se definido, mas vazio, ou não válido, ou se o comando chamado retornar falso, a recursão da árvore será cortada nesse ponto, e somente o nome do diretório é impresso em stdout antes que o nível da recursão da árvore retorne ao anterior.

Pense em cd_tree_callback como algo como uma combinação das primitivas find -exec e -prune .

E o exemplo recursivo very ...

cdtree(){
        set '
#       \eval " \shift 0${3+1};'\
'               $1$1\${1##* } \"\$PWD\" \"\$@\";'\
'       \eval   \"\${1#??}\";}; return"
        cdtree()
                if      OLDPWD=${1%/}   \cd -P -
                then    for  d  in      ./.[!.]*/ ./..?*/ ./*/
                        do      \[ ! -d "$d" -o -h "${d%/}" ] ||
                                \cdtree "${PWD%/}/${d#?/}" "$PWD"
                        done;   \cd -P  "${2:-.}"
                else    \printf %s\n   "${PWD%/}/${1#?/}"
                fi
        while   \[  "${2+1}"  ] &&  \shift
        do      \[ "${1##/*}" ] &&  \set -- "$PWD$@"
                \[  / = "$1"  ] &&  \set -- "/$@"
                d=   \command eval "\cdtree \"\\" \"\$PWD\""
        done
        cdtree(){ \set '\' "$PWD" "$@"
        eval "${1#??}"
}

Eu esqueço o que é chamado quando um programa pode reproduzir totalmente sua própria fonte em tempo de execução ... Há um nome para isso, mas ... ele me escapa. De qualquer forma, é assim que funciona. Primeiro, ele salva basicamente todo o corpo da função e, usando esse valor, define uma nova função cdtree() que pode chamar dentro do loop while para cada arg. Então você pode entregá-lo como muitos args como você gosta, e ele irá reciclar totalmente a árvore para cada um. Quando tudo isso estiver completo, ele se redefine novamente para o seu estado original, de modo que ele faça a mesma coisa da próxima vez que você o chamar.

Aparentemente, é uma espécie de quine ... no entanto, isso não imprima sua origem para produzir, avalie, altere, reproduza e restaure.

    
por 14.01.2016 / 01:01