O que são diretórios ./ e ../?

20

Pergunta simples, mas não sei ao certo onde procurar e o Google não responde a períodos e barras.

Só estou tentando contar o número de arquivos e diretórios no diretório atual (não incluindo subpastas / arquivos) e estava tentando diferenciar ls -1 | wc -le, ls | wc -luma vez que eles parecem idênticos. Um site que eu estava vendo dizia "Lembre-se de que isso também conta os diretórios ./ e ../". em relação àquele com ls -1, e não tenho certeza se isso significa que ele inclui os diretórios antes ou algo assim (o que eu não quero), mas não pareceu fazer isso nos testes.

Alguém poderia confirmar qual seria o mais adequado para contar o número de arquivos e diretórios apenas no diretório atual (não sub) e o que eles significam com diretórios ./ e ../?

Adão
fonte
O "Lembre-se de que isso também está contando os diretórios ./ e ../" está incorreto (a menos que seja um erro de digitação para "." E "..".
Vonbrand

Respostas:

15

Todo diretório em um sistema Unix (e provavelmente todos os outros sistemas também) contém pelo menos duas entradas de diretório. Estes são .(diretório atual) e ..(diretório pai). No caso do diretório raiz, eles apontam para o mesmo local, mas com qualquer outro diretório, eles são diferentes. Você pode ver isso usando os comandos stat, pwde cd(no Linux):

$ cd /
$ stat . .. bin sbin | grep Inode
Device: 802h/2050d      Inode: 2           Links: 27
Device: 802h/2050d      Inode: 2           Links: 27
Device: 802h/2050d      Inode: 548865      Links: 2
Device: 802h/2050d      Inode: 2670593     Links: 2
$ pwd
/
$ cd ..
$ pwd
/
$

Observe que bine sbincada um tem dois links para ele. Uma é a entrada de diretório no diretório raiz e a outra é a .entrada dentro desse diretório.

Usar lsum pipe para wc -lé um truque simples para contar o número de linhas na saída de ls. A suposição é que cada arquivo ou diretório ocupará exatamente uma linha na saída. O GNU ls, quando a saída é não terminal, faz isso automaticamente; outros podem precisar da -1opção de ativar o comportamento explicitamente. wc -lsimplesmente conta e gera o número de linhas ( -l) em sua entrada.

O problema dessa abordagem é que, no Linux e nos sistemas de arquivos tradicionalmente usados ​​no Linux, os nomes de arquivos e diretórios (eles são realmente o mesmo nesse aspecto) podem conter caracteres de nova linha . Na presença deles, qualquer um dos métodos se desfaz - essas entradas serão contadas como duas ou mais entradas quando, na realidade, forem uma.

Desde que você esteja usando o GNU ls, não tenha entradas de diretório com nomes que contenham caracteres de nova linha e não possua aliases ímpares para ls(por exemplo ls -a), ambos produzirão a contagem de arquivos e diretórios no diretório atual (ou especificado). Para a maioria das pessoas, isso é bom o suficiente, mas não é válido no caso geral .

Se você precisar manipular caracteres incomuns (principalmente novas linhas) nos nomes de entrada de diretório corretamente, sugiro usar a -bopção ls para escapar deles. ls -1bAimprimirá cada nome de entrada do diretório em sua própria linha, escapará de caracteres incomuns (para que cada entrada do diretório seja vista como um), incluindo arquivos de ponto e diretórios -d. Escolha wc -luma linha de comando completa, ls -1bA | wc -lque relate o número de arquivos e diretórios no diretório atual (mas ignore .e ..; essa é a diferença entre -ae -A), mas não desça em nenhum subdiretório. Se você não deseja que nenhum arquivo de ponto seja contado no total, simplesmente omita o -Aparâmetro para ls.

um CVn
fonte
Ambos -ae -Aincluem arquivos ocultos, o que eu percebi que quero evitar, então, no máximo, eu faria ls -b | wc -l, mas isso me dá a resposta certa. A linha que copio e colei em relação a este comando está incorreta? Se estivesse correto, eu não deveria estar obtendo uma saída 8 quando houver 6 arquivos ou pastas em um diretório?
Adam
@ Adam Sim, isso provavelmente fará o truque ("ls -b | wc -l"); você também pode usar o "-1" (traço + número um) que força uma listagem em uma única coluna em vez de todas em uma única linha, mas isso acontece de qualquer maneira ao canalizar para outro comando. Então (imho) eu deixaria como "ls -1b | wc -l"; e para "testar", execute "ls -1b" e conte o número de linhas, depois execute "ls -1b | wc -l" e verifique os resultados. (Isso é como tubos de depuração / teste.)
michael
@ Sardathrion, esse FAQ é bastante enganador. As convenções do sistema de arquivos Unix não são "estranhas"; onde eles são comuns, é o outro sistema que os escolhe. Mas tudo bem. Depois, diz que o "comando file usa números mágicos para identificar ...", o que está errado: ele também usa muitas heurísticas. Não é muito confiável no meu livro.
vonbrand 30/01
@ vonbrand: justo, link excluído. Eu apenas passei os dedos e parecia bom. Eu sei que encontrei um que era bom, mas agora não consigo lembrar onde estava.
Sardathrion - Restabelece Monica
11
Você está enganado: . e .. são artefatos históricos do UNIX na década de 1970 e resultam de uma época em que ainda não havia mkdir()chamada do sistema. Nem todos os sistemas de arquivos os possuem e nem são necessários nem exigidos pelo POSIX.
schily
6

Para responder à pergunta no assunto:

Quando um diretório B é criado no Unix, ele é adicionado como uma nova entrada em outro diretório A (seu diretório pai) e, em B, duas entradas são adicionadas: uma chamada .como um link físico para si mesma e uma chamada ..como um disco rígido. link para A.

Esses são os únicos links físicos para diretórios permitidos (embora algumas versões mais antigas de alguns Unices também permitam links arbitrários).

é por isso que na maioria dos sistemas de arquivos ( btrfssendo uma exceção notável), o número linksde um diretório é uma indicação de quantos subdiretórios ele possui (contabilizando suas ..entradas).

Quando você está renomeando / movendo um diretório, se for para o mesmo diretório (com um nome diferente), apenas a entrada de nome Aé alterada. B .e ..não é afetado. Mas se você o mover, faça um diretório diferente, então o ..in Bserá alterado. Isso explica por que você pode renomear um diretório no qual você não tem acesso de gravação (supondo que você tenha acesso de gravação ao diretório pai) apenas desde que não o mova para outro diretório (caso contrário, a necessidade de alterar a ..entrada impede você de movê-lo).

Cuidado, porém: /a/b/../cpode não ser o mesmo, /a/cporque /a/bpode ser um link simbólico para outro diretório.

Uma exceção é quando esse caminho é dado ao cdcomando para alguns shells. Eles cdtratam .. logicamente ignorar as ..entradas nos diretórios. Um motivo pelo qual você vê frequentemente cd -Pem scripts escritos corretamente, para desativar esse recurso que poderia causar confusão e inconsistências.

Para contar o número de entradas no diretório atual, excluindo .e ..com bash, você pode:

shopt -s nullglob dotglob
set -- *
echo "$#"

Com zsh:

f=(*(ND))
echo $#f

Portably:

find . ! -name . -prune -print | grep -c /
Stéphane Chazelas
fonte
Estou um pouco confuso; todos os três listados adicionam um à contagem real. por exemplo, se eu tiver 6 arquivos ou pastas em um diretório, eles saída 7, não 6. Para mim, parece que ls | wc -lé a única exclusão .e..
Adam
11
@ Adam, lsnão lista arquivos ocultos. Você precisa ls -Aobter o mesmo que esses. Se você não quiser contar os arquivos ocultos, retire o dotglob(para bash) ou D(para zsh) ou adicione um ! -name '.*'antes -printpara find.
Stéphane Chazelas
Sim, acabei de perceber isso depois de listar os arquivos. Você sabe por que ls | wc -lainda me dá a resposta certa e exclui arquivos ocultos, .& ..?
Adam
11
Adam, em seu diretório, você tem ., ..e outro arquivo cujo começa nome com .o qual não está listado por ls mas seria por ls -A. Portanto ls | wc -l, não fornece a resposta correta, porque não está contando esse arquivo oculto.
Stéphane Chazelas
11
Sim, .e ..são arquivos ocultos, pois começam com a .. Existe até uma lenda que explica que os dotfiles são ocultados por acidente, pois uma implementação inicial de lsera para excluir apenas .e .., mas houve um bug que fez com que ele excluísse qualquer arquivo começando com .. ls | wc -lnão funciona se os nomes de arquivos contiverem caracteres de nova linha.
Stéphane Chazelas
1

Eu não sou um grande especialista em Linux, mas conheço o Linux (costumava ser administrador há 16 anos, no Slackware :) bons velhos tempos

os diretórios ./ e ../ é simples:. é o diretório atual, .. é o diretório anterior (na árvore de pwd -local directory command-

Se contar, acho que eles adicionam 2 ao total da listagem, na verdade não vão recursivamente e contam o diretório abaixo do atual e também contam novamente o diretório atual (.) :))

Então, basicamente, acho que agrega o valor 2 para já contar (arquivos) no diretório atual.

Alguém me corrija se eu estiver errado.

Estou apenas postando para ajudar e, visto que ninguém respondeu a essa pergunta aqui, eles podem estar ocupados. Mas experimente e veja se você tem 10 arquivos e conte 12, então é isso.

Adrian Tanase
fonte
Sim, Adrian está correto:. é o diretório atual e .. é o diretório imediatamente acima na hierarquia.
schaiba
.. nem sempre se refere ao diretório anterior na árvore: em "/" .. refere-se também ao diretório atual.
Bonsi Scott
porque você pode estar no / root do sistema de arquivos?
Adrian Tanase
Se adicionar dois ao número de arquivos em um diretório, por que estou recebendo a resposta correta ao testá-lo no terminal no osx? por exemplo, um diretório com 6 arquivos ou pastas serão saída 6, não 8 quando eu façols | wc -1
Adam
Percebi que é porque eles estão incluindo arquivos ocultos (ou seja, .ds_store), mas ainda não vejo como ls | wc -linclui .e ..quando obtenho a resposta certa, em oposição à resposta correta. + #
Adam