CP поводиться дивно, коли. (крапка) або .. (крапка) - це вихідний каталог


15

Ця відповідь показує, що можна копіювати всі файли, включаючи приховані, з каталогу srcв каталог destтак:

mkdir dest
cp -r src/. dest

У відповіді чи коментарях немає пояснень, чому це насправді працює, і, здається, ніхто також не знайде документації на це.

Я спробував кілька речей. По-перше, звичайний випадок:

$ mkdir src src/src_dir dest && touch src/src_file src/.dotfile dest/dest_file
$ cp -r src dest
$ ls -A dest
dest_file  src

Потім, /.в кінці:

$ mkdir src src/src_dir dest && touch src/src_file src/.dotfile dest/dest_file
$ cp -r src/. dest
$ ls -A dest
dest_file  .dotfile  src_dir  src_file

Отже, це поводиться просто *, але також копіює приховані файли.

$ mkdir src src/src_dir dest && touch src/src_file src/.dotfile dest/dest_file
$ cp -r src/* dest
$ ls -A dest
dest_file  src_dir  src_file

.і ..є належними жорсткими посиланнями, як пояснено тут , як і сам запис каталогу.

Звідки ця поведінка, і де це зафіксовано?


3
Що ти означає, що ніхто не може знайти документацію? cpПосилання ясно пояснює , як cp -Rпрацює. .і ..це каталоги, як і будь-які інші каталоги, в них немає нічого магічного та загадкового.
AlexP

2
@AlexP Я відредагував відповідь, щоб зробити її зрозумілішою. Вся справа в тому, що .і ..не вести себе як інші каталоги.
iFreilicht

Я спробував пояснити, чому це працює в розділі Як рекурсивно копіювати папку
безвідмовно,

Відповіді:


27

Поведінка є логічним результатом документально підтвердженого алгоритму cp -R . Див. POSIX , крок 2f:

Файли в каталозі source_file повинні бути скопійовані в каталог dest_file , виконуючи чотири кроки (від 1 до 4), перераховані тут, з файлами як вихідні файли .

.і ..є каталогами відповідно поточного каталогу та батьківського каталогу. Що стосується оболонки, вони не є спеціальними, тому розширення не стосується жодного, і каталог буде скопійовано, включаючи приховані файли. *з іншого боку, буде розширено до списку файлів, і саме там приховані файли фільтруються.

src/.- поточний каталог всередині src, який є srcсамим собою; src/src_dir/..це src_dirбатьківський каталог, який знову є src. Тож ззовні src, якщо srcце каталог, вказуючи src/.або src/src_dir/..як вихідний файл дляcp еквівалента, скопіюйте вміст src, включаючи приховані файли.

Сенс уточнення src/.полягає в тому, що він не вийде, якщо srcце не каталог (або символічне посилання на каталог), тоді як srcне буде. Він також буде копіювати вміст srcлише, не копіюючи srcсебе; це також відповідає документації:

Якщо ціль існує та називає існуючий каталог, ім'я відповідного шляху призначення для кожного файлу в ієрархії файлів має бути конкатенацією цілі , одним символом похилої риси, якщо ціль не закінчується косою рисою, та іменем шляху відносного файлу до каталогу, що містить source_file .

Так cp -R src/. destкопіює вміст srcв dest/.(вихідний файл знаходиться .в src), в той час як cp -R src destкопіює вміст srcвdest/src (вихідний файл src).

Інший спосіб думати про це - порівняти копіювання src/src_dirі src/., а не порівнювати src/.і src. .поводиться так само, як src_dirу колишньому випадку.


Але це не так поводиться. Вказавши src, скопіюйте каталог dest, src/.скопіюйте вміст. Я спробую зробити це яснішим у питанні.
iFreilicht

Там, я думаю, це відповідає на ваше основне запитання.
Стівен Кітт

1
@ Stéphane OP порівнює копіювання src/.та src/*(зауважте, не src/.* ); src/*не включає приховані файли, якщо глобус їх ігнорує ...
Стівен Кітт

1
Хм, "каталог, що містить вихідний файл ". Ну, очевидно, srcміститьsrc/. але це означає, що містить каталог каталогу залежить від того, як ви називаєте каталог. Звичайно, існування .посилань певним чином означає, що всі каталоги містять себе, але це може бути не інтуїтивно зрозумілим для всіх. Замість такої поведінки можна також спокусити припустити, що "каталог, що містить каталог foo", визначатиметься тим foo/.., що в цьому випадку було б неважливо, ми посилаємось на : fooабо foo/.результат, що містить каталог, був би таким самим.
ilkkachu

1
Що означає, що відмінність між собою fooі foo/.здається делікатною, але я не заперечую, я також вважаю це трохи кумедно.
ilkkachu

1

Коли ти побіжиш cp -R src/foo dest, отримаєш dest/foo. Отже, якщо каталог dest/fooне існує, cpстворіть його, а потім скопіюйте вміст src/fooуdest/foo .

Коли ви запускаєте cp -R src/. dest, cpбачить, що dest/.існує, і тоді справа лише в тому, щоб скопіювати вміст src/.доdest/. .

Коли ви думаєте про нього , як копіювання каталогу з ім'ям .з srcі об'єднання його вміст існуючого каталогу dest/., це буде мати сенс.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.