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.