Co to są katalogi ./ i ../?

20

Proste pytanie, ale nie jestem pewien, gdzie szukać, a Google nie reaguje na kropki i ukośniki.

Po prostu próbuję policzyć # plików i katalogów w bieżącym katalogu (nie licząc podfolderów / plików) i starał się różnicować ls -1 | wc -li ls | wc -lponieważ wydają identyczne. Witryna, na którą patrzyłem, powiedziała: „Pamiętaj, że to także uwzględnia katalogi ./ i ../”. jeśli chodzi o ten z ls -1, i nie jestem pewien, czy to oznacza, że ​​zawiera katalogi wcześniej czy coś (czego nie chcę), ale wydaje się, że nie robiło to z testowania.

Czy ktoś mógłby potwierdzić, który z nich byłby najbardziej odpowiedni do zliczania # plików i katalogów tylko w bieżącym katalogu (nie sub) i co rozumieją przez katalogi ./ i ../?

Adam
źródło
„Pamiętaj, że to także liczy katalogi ./ i ../” jest błędne (chyba że jest to literówka dla „.” I „..”.
vonbrand 30.01.2013

Odpowiedzi:

15

Każdy katalog w systemie Unix (i prawdopodobnie także każdy inny system) zawiera co najmniej dwie pozycje katalogu. Są to .(katalog bieżący) i ..(katalog macierzysty). W przypadku katalogu głównego wskazują one to samo miejsce, ale w każdym innym katalogu są one różne. Można to zobaczyć na własne oczy użyciu stat, pwdi cdpolecenia (w systemie 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
/
$

Uwaga, bini sbinkażdy ma dwa linki do niego. Jeden to wpis katalogu w katalogu głównym, a drugi to .wpis w tym katalogu.

Używanie lsz potokiem do wc -ljest prostą sztuczką, aby policzyć liczbę linii na wyjściu ls. Zakłada się, że każdy plik lub katalog zajmie dokładnie jeden wiersz na wyjściu. GNU ls zrobi to, gdy wyjście nie jest terminalem, zrobi to automatycznie; inni mogą potrzebować -1opcji jawnego włączenia zachowania. wc -lpo prostu zlicza i wypisuje liczbę wierszy ( -l) na wejściu.

Problem z tym podejściem polega na tym, że w systemie Linux i systemach plików tradycyjnie używanych w systemie Linux, nazwy plików i katalogów (w tym przypadku są one naprawdę takie same) mogą zawierać znaki nowej linii . W ich obecności jedna z metod się rozpada - wpisy te będą liczone jako dwa lub więcej wpisów, podczas gdy w rzeczywistości są one jednym.

Tak długo, jak używasz GNU ls, nie ma pozycji katalogu z nazwami zawierającymi znaki nowego wiersza i nie ma nieparzystych aliasów dla ls(na przykład ls -a), oba będą wyświetlać liczbę plików i katalogów w bieżącym (lub określonym) katalogu. Dla większości ludzi jest to wystarczająco dobre, ale nie jest to poprawne w ogólnym przypadku.

Jeśli potrzebujesz poprawnie obsługiwać nietypowe znaki (przede wszystkim znaki nowej linii) w nazwach pozycji katalogu, sugeruję użycie -bopcji ls, aby je uciec. ls -1bAwypisze nazwę każdego wpisu katalogu we własnym wierszu, unikając nietypowych znaków (więc każdy wpis katalogu będzie postrzegany jako jeden), w tym wszelkie pliki-kropkowe i -katalogi. Dołącz wc -ldo pełnego wiersza poleceń, ls -1bA | wc -lktóry zgłosi liczbę plików i katalogów w bieżącym katalogu (ale zignoruj .i ..; to różnica między -ai -A), ale nie zejdzie do żadnych podkatalogów. Jeśli nie chcesz, aby pliki dot były liczone do sumy, po prostu pomiń -Aparametr do ls.

CVn
źródło
Zarówno -ai -Azawierać ukryte pliki, a które ja sobie sprawę, chcę uniknąć, więc co najwyżej bym zrobiła ls -b | wc -l, ale to nie daje mi właściwą odpowiedź. Czy wiersz, który kopiuję i wklejam odnośnie tego polecenia jest niepoprawny? Jeśli było to prawidłowe, czy nie powinienem otrzymywać danych wyjściowych o wartości 8, gdy w katalogu znajduje się 6 plików lub folderów?
Adam
@Adam tak, to prawdopodobnie załatwi sprawę ("ls -b | wc -l"); możesz również użyć „-1” (myślnik + cyfra jeden), który wymusza wyświetlanie w jednej kolumnie zamiast wszystkich w jednym wierszu, ale dzieje się tak mimo to podczas przesyłania potokiem do innego polecenia. Więc (imho) zostawiłbym to jako „ls -1b | wc -l”; i aby „przetestować”, uruchom „ls -1b” i policz liczbę linii, a następnie uruchom „ls -1b | wc -l” i sprawdź wyniki. (Tak właśnie debuguje / testuje rury.)
Michael
@Sardathrion, to FAQ jest dość mylące. Konwencje uniksowego systemu plików nie są „dziwne”; tam, gdzie są wspólne, inny system je odbiera. Ale ok. Następnie mówi, że „polecenie pliku używa magicznych liczb do identyfikacji ...”, co jest błędne: używa również dużej heurystyki. Niezbyt wiarygodne w mojej książce.
vonbrand
@vonbrand: wystarczy, link usunięty. Właśnie go przejrzałem i wydawało się, że jest w porządku. Wiem, że znalazłem taki, który był dobry, ale teraz nie pamiętam, gdzie to było.
Sardathrion - Przywróć Monikę
1
Mylisz się: . i .. są historycznymi artefaktami z systemu UNIX w latach 70. XX wieku i wynikają z czasów, gdy jeszcze nie było mkdir()wywołania systemowego. Nie wszystkie systemy plików je mają i nie są nawet potrzebne ani wymagane przez POSIX.
schily
6

Aby odpowiedzieć na pytanie w temacie:

Kiedy katalog B jest tworzony w Uniksie, jest dodawany jako nowy wpis do innego katalogu A (jego katalogu nadrzędnego), aw B dodawane są dwa wpisy: jeden nazywany .twardym łączem do siebie, a drugi nazywany ..twardym link do A.

Są to jedyne dozwolone twarde linki do katalogów (chociaż niektóre starsze wersje niektórych Uniksów również dopuszczały dowolne linki).

dlatego w większości systemów plików ( btrfsco jest godnym uwagi wyjątkiem) numer linkskatalogu wskazuje, ile ma podkatalogów (uwzględniając ich ..wpisy).

Gdy zmieniasz nazwę / przenosisz katalog, jeśli znajduje się on w tym samym katalogu (pod inną nazwą), Azmieniany jest tylko wpis w nazwie . B .i ..nie ma to wpływu. Ale jeśli przenieść to zrobić inny katalog, a następnie ..w Bulegnie zmianie. To wyjaśnia, dlaczego możesz zmienić nazwę katalogu, do którego nie masz dostępu do zapisu (zakładając, że masz dostęp do zapisu do katalogu nadrzędnego) tylko pod warunkiem, że nie przeniesiesz go do innego katalogu (w przeciwnym razie potrzeba zmiany ..wpisu uniemożliwi od przeniesienia go).

Uważaj jednak: /a/b/../cnie może być taka sama jak /a/cbo /a/bmoże być symboliczny link innego katalogu.

Wyjątkiem jest sytuacja, w której ta ścieżka jest podawana do cdpolecenia dla niektórych powłok. Te cds traktować .. logicznie ignorowanie ..wpisów w katalogach. Powód, dla którego często widzisz cd -Ppoprawnie napisane skrypty, aby wyłączyć tę funkcję, która w przeciwnym razie mogłaby powodować zamieszanie i niespójności.

Aby policzyć liczbę wpisów w bieżącym katalogu bez .i ..ze bashmożna zrobić:

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

Z zsh:

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

Przenośny:

find . ! -name . -prune -print | grep -c /
Stéphane Chazelas
źródło
Jestem trochę zmieszany; wszystkie trzy wymienione przez ciebie osoby dodają jeden do rzeczywistej liczby. np. jeśli mam 6 plików lub folderów w katalogu, wyprowadzają one 7, a nie 6. Wydaje mi się, że ls | wc -ljest to jedyny wykluczający .i..
Adam
1
@Adam, lsnie wyświetla ukrytych plików. Musisz ls -Auzyskać takie same jak te. JEŻELI nie chcesz liczyć ukrytych plików, zdejmij dotglob(dla bash) lub D(dla zsh) lub dodaj ! -name '.*'przedtem -printdla find.
Stéphane Chazelas,
Tak, właśnie to zauważyłem po faktycznym wylistowaniu plików. Czy wiesz, dlaczego ls | wc -lwciąż daje mi właściwą odpowiedź i wyklucza ukryte pliki, .i ..?
Adam
1
Adam w swoim katalogu, masz ., ..a inny plik, którego nazwa zaczyna się ., które nie jest wymienione przez ls ale byłoby za ls -A. Więc ls | wc -lnie daje poprawnej odpowiedzi, ponieważ nie liczy tego ukrytego pliku.
Stéphane Chazelas,
1
Tak, .i ..są ukrytymi plikami, ponieważ zaczynają się od .. Istnieje nawet legenda, która wyjaśnia, że dotfiles ukryte przez przypadek jako wczesne wdrożenie lsmiało na celu wykluczenie tylko .a .., ale nie był to błąd, który powodował, że aby wykluczyć wszystkie pliki zaczynające się .. ls | wc -lnie działa, jeśli nazwy plików zawierają znaki nowego wiersza.
Stéphane Chazelas
1

Nie jestem świetnym ekspertem od Linuksa, ale znam Linuksa (byłam administratorem 16 lat temu na Slackware :) Dobry stary czas

katalogi ./ i ../ to proste:. jest bieżącym katalogiem, .. jest poprzednim katalogiem (w drzewie pwd -local katalog polecenie-

Jeśli to się liczy, liczę, że dodają 2 do całej listy, tak naprawdę nie przechodzą rekurencyjnie i liczą katalog poniżej bieżącego, a także liczą ponownie bieżący katalog (.) :))

Zasadniczo myślę, że dodaje wartość 2 do liczenia (plików) w bieżącym katalogu.

Niech ktoś mnie poprawi, jeśli się mylę.

Po prostu piszę, aby pomóc i zobaczyłem, że nikt tutaj nie odpowiedział na to pytanie, mogą być zajęci. Ale po prostu eksperymentuj i sprawdź, czy masz 10 plików i uzyskaj liczbę 12, to wszystko.

Adrian Tanase
źródło
Tak, Adrian ma rację:. to bieżący katalog, a .. to katalog znajdujący się bezpośrednio nad hierarchią.
schaiba
.. nie zawsze odnosi się do poprzedniego katalogu w drzewie: w „/” .. odnosi się również do bieżącego katalogu.
Bonsi Scott,
ponieważ możesz być w / root systemu plików?
Adrian Tanase
Jeśli dodaje dwa do # plików w katalogu, dlaczego otrzymuję poprawną odpowiedź podczas testowania w terminalu na OSX? np. katalog z 6 plikami lub folderami wyświetli 6, a nie 8, kiedy to zrobięls | wc -1
Adam
Uświadomiłem sobie, że dzieje się tak dlatego, że zawierają ukryte pliki (a mianowicie .ds_store), ale nadal nie widzę, w jaki sposób ls | wc -lzawiera .i ..kiedy otrzymuję właściwą odpowiedź, w przeciwieństwie do właściwej odpowiedzi + 2.
Adam