Eu entendo que ls -R
exibe uma lista de diretórios. Mas por que é recursivo? Como a recursão é usada no processo?
command-line
ls
Mint.K
fonte
fonte
ls
encontra um diretório, ele recursivamente lista esse diretório.Respostas:
Primeiro, vamos definir uma estrutura de pastas arbitrária:
Quando o fazemos
ls
, obtemos apenas a saída da pasta base:No entanto, quando ligamos
ls -R
, obtemos algo diferente:Como você pode ver, ele está sendo executado
ls
na pasta base e depois em todas as pastas filho. E todas as pastas de netos, ad infinitum. Efetivamente, o comando percorre cada pasta recursivamente até atingir o final da árvore de diretórios. Nesse ponto, ele retorna uma ramificação na árvore e faz o mesmo para todas as subpastas, se houver.Ou, no pseudocódigo:
E porque eu posso, uma implementação Java de referência do mesmo.
fonte
Com efeito, existem duas perguntas intimamente ligadas que você pode estar fazendo.
ls
? Do seu fraseado ("Como a recursão é usada no processo?"), Acho que isso faz parte do que você deseja saber. Esta resposta aborda essa questão.Por que faz sentido
ls
ser implementado com uma técnica recursiva:O FOLDOC define recursão como:
A maneira natural de implementar
ls
é escrever uma função que construa uma lista de entradas do sistema de arquivos a serem exibidas e outro código para processar argumentos de caminho e opção e exibir as entradas conforme desejado. É altamente provável que essa função seja implementada recursivamente.Durante o processamento da opção,
ls
determinará se foi solicitado a operar recursivamente (sendo invocado com o-R
sinalizador). Nesse caso, a função que cria uma lista de entradas a serem exibidas se chamará uma vez para cada diretório listado, exceto.
e..
. Pode haver versões recursivas e não recursivas separadas dessa função, ou a função pode verificar cada vez se é suposto estar operando recursivamente.O Ubuntu
/bin/ls
, o executável que é executado quando você executals
, é fornecido pelo GNU Coreutils e possui muitos recursos. Como resultado, seu código é um pouco mais longo e mais complicado do que você imagina. Mas o Ubuntu também contém uma versão mais simplesls
, fornecida pelo BusyBox . Você pode executar isso digitandobusybox ls
.Como
busybox ls
usa a recursão:ls
no BusyBox é implementado emcoreutils/ls.c
. Ele contém umascan_and_display_dirs_recur()
função que é chamada para imprimir uma árvore de diretórios recursivamente:A linha onde a chamada de função recursiva ocorre é:
Vendo as chamadas de função recursiva à medida que acontecem:
Você pode ver isso em operação se você executar
busybox ls
em um depurador. Primeiro instalar os símbolos de depuração por permitindo pacotes -dbgsym.ddeb e, em seguida, instalar obusybox-static-dbgsym
pacote. Instalegdb
também (esse é o depurador).Eu sugiro a depuração
coreutils ls
em uma árvore de diretórios simples.Se você não tiver um, faça um (isso funciona da mesma maneira que o
mkdir -p
comando na resposta do WinEunuuchs2Unix ):E preencha-o com alguns arquivos:
Você pode verificar as
busybox ls -R foo
obras conforme o esperado, produzindo esta saída:Abra
busybox
no depurador:O GDB imprimirá algumas informações sobre si mesmo. Então deve dizer algo como:
(gdb)
é o seu prompt no depurador. A primeira coisa que você instruirá o GDB a fazer nesse prompt é definir um ponto de interrupção no início dascan_and_display_dirs_recur()
função:Quando você executa isso, o GDB deve dizer algo como:
Agora diga ao GDB para executar
busybox
com (ou qualquer nome de diretório que você deseja) como seus argumentos:ls -R foo
Você pode ver algo assim:
Se você vir
No such file or directory
, como acima, tudo bem. O objetivo desta demonstração é apenas ver quando ascan_and_display_dirs_recur()
função foi chamada, para que o GDB não precise examinar o código-fonte real.Observe que o depurador atingiu o ponto de interrupção antes mesmo de qualquer entrada de diretório ser impressa. Ele interrompe a entrada dessa função, mas o código nessa função deve ser executado para que todos os diretórios sejam enumerados para impressão.
Para dizer ao GDB para continuar, execute:
Cada vez que
scan_and_display_dirs_recur()
é chamado, o ponto de interrupção será atingido novamente, para que você veja a recursão em ação. Parece com isso (incluindo o(gdb)
prompt e seus comandos):A função tem
recur
seu nome ... o BusyBox a usa somente quando a-R
bandeira é fornecida? No depurador, é fácil descobrir:Mesmo sem
-R
essa implementação específica,ls
a mesma função é usada para descobrir quais entradas do sistema de arquivos existem e mostrá-las.Quando você quiser sair do depurador, diga-o:
Como
scan_and_display_dirs_recur()
sabe se deve se chamar:Especificamente, como funciona de maneira diferente quando a
-R
bandeira é passada? Examinar o código fonte (que pode não ser a versão exata no seu sistema Ubuntu) revela que ele verifica sua estrutura interna de dadosG.all_fmt
, onde armazena com quais opções ele foi chamado:(Se o BusyBox tiver sido compilado sem suporte
-R
, ele também não tentará exibir as entradas do sistema de arquivos recursivamente; é disso queENABLE_FEATURE_LS_RECURSIVE
se trata a parte.)Somente quando
G.all_fmt & DISP_RECURSIVE
verdadeiro, o código que contém a chamada de função recursiva é executado.Caso contrário, a função será executada apenas uma vez (por diretório especificado na linha de comandos).
fonte
Quando você pensa sobre isso, "recursivo" faz sentido para comandos que atuam em diretórios e seus arquivos e diretórios e seus arquivos e diretórios e seus arquivos e diretórios e seus arquivos .........
.... até que toda a árvore do ponto especificado para baixo tenha sido operada pelo comando, neste caso, listando o conteúdo de qualquer subdiretório de qualquer subdiretório de qualquer subdiretório .......... que exista sob o comando argumento (s) do comando
fonte
-R é para recursão, que poderia ser chamada "repetidamente".
Veja este código, por exemplo:
Os
-p
diretórios em criação permitem criar diretórios em massa com um único comando. Se um ou mais dos diretórios superior-intermediário já existir, não será um erro e os diretórios inferior-médio serão criados.Em seguida, a
ls -R
lista recursiva de todos os diretórios começa com temp e funciona da árvore para todos os ramos.Agora vamos ver um complemento para o
ls -R
comando, ou seja, otree
comando:Como você pode ver
tree
realiza o mesmo quels -R
exceto é mais conciso e ouso dizer "mais bonita".Agora vamos ver como remover recursivamente os diretórios que acabamos de criar em um comando simples:
Isso remove recursivamente
temp
e todos os subdiretórios abaixo dele. ou sejatemp/a
,temp/b/1
etemp/c/1/2
mais os diretórios do meio entre os dois.fonte
tree
. É uma ótima ferramenta.Aqui está uma explicação simples, faz sentido, porque quando se trata de exibir o conteúdo de subdiretórios, a mesma função já sabe o que fazer com um diretório. Portanto, ele só precisa se chamar em cada subdiretório para obter esse resultado!
No pseudocódigo, é algo como isto:
fonte