Чому при копіюванні каталогу в Linux потрібен -r рекурсивний режим?


47

Моє запитання, чому потрібно використовувати -rпрапор (рекурсивний) під час створення копії каталогу? Тобто навіщо це робити:

$ cp -r dir1 copyDir1

Коли я не хотів би такої поведінки під час копіювання каталогу?

Чи не рекурсивна копія каталогу справді не є поведінкою за замовчуванням; поведінки, якої ми хочемо майже весь час?

Складається враження, що це зайвий прапор.


Чи не потрібно вам також копіювати файли та папку?
QuyNguyen2013

Якщо ви думаєте, що це буде вдосконаленням, можете надіслати цей запит на каналі розробників. Інакше це було, мабуть, запрограмовано давно.
блогер

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


Те саме стосуєтьсяrm

Відповіді:


58

У тому, як файлові системи працюють, каталог насправді не є папкою, що містить файли, а скоріше каталог - це файл, який містить покажчики inode на підключені до нього «дочірні» файли. Значення, з точки зору файлової системи, файл - це файл, але каталог - це лише файл, що містить список підключених файлів.

Отже, з точки зору командного рядка, виконуючи це:

$ cp dir1 copyDir1

По суті, це означатиме скопіювати названий файл dir1у новий ім'я copyDir1. Що ж стосується файлової системи, то dir1це все-таки лише файл; той факт, що це "каталог", стане очевидним лише тоді, коли файлова система насправді перевірить, чи є насправді dir1ця купа біт.

-rПрапор вказує файлову систему рекурсивно скочуються файл / дерево каталогів і копіювати будь-які і всі вміст , яке може бути «дитина» з цього файлу на нове місце.

Тепер, чому це може здатися зайвим або зайвим, це дійсно зводиться до історичних методів роботи з файловими системами. А також створення системи, захищеної від усіх типів помилок, пов’язаних з користувачем; випадкові, а також навмисні.

Тобто, скажімо, ~/binу вашому домашньому каталозі є файл, який ви хочете скопіювати, але випадково його ~випало - тому що ви людина і помилитесь - так це саме /binтак:

cp /bin/ ~/copy_of_bin

Завдяки тому, що «мережа безпеки» /binє каталогом у поєднанні з потребою у -rпрапорі, ви уникнете випадкового копіювання всього бінарного кореня системи, на якій ви перебуваєте, у свій домашній каталог. Якщо цієї мережі безпеки не існувало, трапилося б незначне - або, можливо, велике - катастрофа.

Логіка тут полягає в тому, що за днів до GUI (графічних інтерфейсів користувача) необхідно встановлювати логічні / поведінкові умови, щоб уникнути випадків, коли користувач може створити випадки, які потенційно можуть вбити систему. І використання -rпрапора зараз є одним із них.

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

Але, що стосується сфери текстових інтерфейсів, багато «досвіду користувачів» у цьому світі є в основному просто логічними та ґеристськими дорожніми ударами, що допомагають контролювати користувача, щоб запобігти потенційній катастрофі.

Так само, тому у файлових системах Linux / Unix не встановлено 777дозволів і sudoправ, встановлених за замовчуванням, і як реальні системні адміністратори бажають, коли користувач встановлює 777дозволи або надає всі sudoправа. Це основні речі, які потрібно зробити, щоб забезпечити стабільність системи та максимально «захист від користувачів»; той, хто поспішає на коротке замикання цих конвенцій, швидше за все, завдасть шкоди їхній системі, навіть не підозрюючи про це.

ДОДАТКОВІ ІНФОРМАЦІЇ: Ще одна відповідь тут, на сайті Unix Stack Exchange, дає хороші пояснення, чому нерекурсивна копія каталогу є проблематичною; акцент мій.

Ну а без прапора -R копіювати файли можливо лише тому, що досить незвично, що хтось хоче нерекурсивно копіювати каталог: Нерекурсивна копія просто призведе до другого імені для каталогу, вказуючи безпосередньо на та ж структура каталогів. Оскільки це рідко те, чого хочуть люди, і насправді існує окрема програма, яка робить це (ln), нерекурсивна копія каталогів заборонена.

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


19
Я особисто думаю, що аспект його захисту не проходить перевірку запаху. Один чоловік може так само легко ввести в cp -r /binякості cp-r ~/bin. Сам прапор не запобігає помилкам або обов’язково робить когось кращим, щоб бути обережним. Якщо ви хотіли запобігти помилкам, команда cp може так само легко переглядати відповідний вузол і надати підказку, щось уздовж рядка "Це каталог, чи хочете ви скопіювати весь вміст у вказане місце (y / п)? " Це була б мережа безпеки . Вимагаючи -r для каталогів більше, ніж що-небудь, зменшує розширення коду.
JDL

12
Погана аналогія з люком. Як сказав @JDL, відповідний прапор нічого не запобігає друку на шляху. Мені було б щасливіше сприймати узгодженість з іншими командами як причину, але я маю відчуття, що справжня причина полягає в тому, що "це було написано спочатку, а тепер так багато речей покладається на таку поведінку, змінювати це неможливо".
Основні

7
Коли ми переміщуємо каталог, нам не потрібен -r. Я думаю, що відповідна відповідь на unix.stackexchange.com набагато більш суттєва. Еквівалентом нерекурсивної копії було б мати другий каталог та жорсткі посилання для всіх файлів у дереві каталогів.
Герріт

2
Якщо я не помиляюсь, -r був розширенням GNU - я не думаю, що в історичному cp UNIX була рекурсивна копія - і це було частиною причини для команди rsync .
Май

2
@JakeGould Я розумію основні поняття. Однак я заперечую проти ідеї, що прапор -r у відповідній команді забезпечує додаткову безпеку. З мого досвіду, команди Linux для командних рядків історично суттєво небезпечні. Безпека додається понаднормово, якщо взагалі. Безпека, притаманна дизайну Linux, виходить із системи дозволів і що працює як root. Не працювати як root - це теж щось, що є більше умовою, ніж дизайном. Конвенція підтримується у більшості нових інсталяторів Linux, але не завжди.
JDL

19

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

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

Ключовий фрагмент головоломки тут розуміє, що cpне копіює каталоги - cpкопіює файлилише файли). Якщо ви хочете скопіювати каталог, cp викликує себе рекурсивно , щоб скопіювати файли у кожен каталог.

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

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

Ще одна перевага полягає в тому, що наявність -rтакож допомагає користувачеві зрозуміти, що насправді відбувається під інтерфейсом. Приємним побічним ефектом цього є те, що вивчення концепції рекурсивної роботи позбавить вас від певної роботи, коли ви дізнаєтесь про інші інструменти, які її підтримують (наприклад grep, наприклад)


Деякі люди, безумовно, скажуть вам, що розкривати інформацію про впровадження користувачеві погано і що мати більше можливостей - це добре . Мій намір тут - просто пояснення обґрунтування такої поведінки, тому я не намагатимусь сперечатися в будь-якому випадку.


2
+1 "... зробіть одне і зробіть це добре ..." Дякую, що ви заявили про це!
JakeGould

5

Взаємодія з каталогами гарантує, що ви знаєте, що взаємодієте з каталогом, а НЕ лише одним файлом.

Наприклад:

$ tree
.
└── folder1
    └── sub1
        └── subsub1

3 directories, 0 files
$
$ cp folder1/ folder2
cp: folder1/ is a directory (not copied).
$
$ mkdir blah
$ cp blah/ blah2
cp: blah/ is a directory (not copied).
$ rm blah/
rm: blah/: is a directory

Отже, якщо ви хочете вдало скопіювати папку, оскільки вона передбачає як папку, так і об’єкти, пов’язані з посиланням на папку, ви повинні ставитися до неї як до колекції файлів:

$ cp -r folder1/ folder2
$ rm -rf folder1

3

Наслідком зміни за замовчуванням буде те, що тисячі скриптів оболонок будуть зламані. Це призводить до вимог POSIX та SUS щодо добре відомої поведінки за замовчуванням.

Причина - історична розробка команд cp, ln та mv (все ті ж бінарні для більшості старих систем UNIX) у різних галузях UNIX. Коли -rз'явилася (раніше cpне було можливості копіювати каталоги; ось рання сторінка cp man без -rабо -R), існували різні відмінності в обробці спеціальних файлів, символьних посилань та інших капризів файлової системи.

Із специфікацій бази відкритої групи випуск 7 :

Раніші версії цього стандарту включали підтримку опції -r для копіювання ієрархій файлів. Варіант -r - це історична практика на системах, отриманих BSD та BSD. Цей параметр більше не визначений POSIX.1-2008, але може бути присутнім у деяких реалізаціях. Опція -R була додана як близький синонім до параметра -r, вибрана для узгодження з усіма іншими параметрами в цьому томі POSIX.1-2008, які роблять рекурсивне походження каталогу.

Різниця між -R та вилученим -r варіантом полягає в обробці cp типів файлів, відмінних від звичайних та каталогів. Було визначено реалізацією, як варіант - обробляє спеціальні файли, щоб дозволити як історичні реалізації, так і ті, які вирішили підтримувати -r з тими ж здібностями, що і -R, визначені цим обсягом POSIX.1-2008. Оригінальний прапор -r з історичних причин не обробляв спеціальні файли інакше, ніж звичайні файли, але завжди читав файл і копіював його вміст. Це мало очевидні проблеми за наявності спеціальних типів файлів; наприклад, символьні пристрої, FIFO та розетки.

Насправді ви все ще побачите, що деякі люди регулярно використовують:

cd dir1 ; tar -cf - . | (cd dir2 ; tar -xpf -)

Тому що вони не вірять, що cp -rреалізація буде такою, до якої вони звикли на довільній машині; Або тому, що вони хочуть tarповедінки.


3

Сьогодні це може бути субоптимальним інтерфейсом, але це рішення було прийнято приблизно в 1970 році під час проектування UNIX, коли диск був значно дорожчим. Мільйони скриптів оболонок залежать від того, як він працює таким чином, і змінити його ще пізно.

Дивіться цю статтю для оригінальної інформації про дизайн.


3

Очевидною перевагою -rпрапора є те, що ви можете cp * /target/dirскопіювати лише всі файли з вихідного каталогу в цільовий каталог, опустивши (хоча і з попередженням) всі каталоги, що містяться в ньому. cp -r * /target/dirскопіював би все, включаючи підкаталоги.


2

Цей прапор вам потрібен лише тоді, коли cpце команда для копіювання файлів та каталогів, а не лише каталогів.

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


1
Має сенс. Але чому б хтось копіював каталог, у якому немає хоча б одного файлу? Чому б тоді просто не використовувати mkdir?
JakeGould

1
@JakeGould, можливо, тому, що їм може знадобитися зберегти право власності та дозволи?
Руслан

1

Як вже згадували інші, каталог - це лише інший тип файлів (на відміну від звичайного файлу), який зазвичай "містить" (вказує на) інші файли. Він може містити підкаталоги, до яких те саме стосується ...

Отже, якщо ви копіюєте каталог (перспектива користувача), ви дійсно копіюєте купу файлів (перспектива файлової системи) (звичайні файли, файли каталогів, символічні посилання, ...) і для кожного файлу каталогів ви рекурсивно повторюєте це процес. Оскільки копіювання каталогу за визначенням є рекурсивним процесом, викликається аргумент cp --recursive.

Звичайно, дуже просто створити ярлик команди у своєму користувальницькому середовищі (помістіть це у свій .profile / .bashrc файл, щоб він був постійно доступним):

alias cpr='cp -r'

А може, краще:

alias cpa='cp -av'

Таким чином, ви можете скопіювати каталог за допомогою, cpa dir1 copyDir1і він буде не тільки друкувати те, що копіюється, але й застосовувати дозволи файлів.

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

cp()
{
    if [ ! -e "$1" ]; then
        echo missing source file
        return 1
    fi
    arg="-d --preserve=all -v"
    if [ -d "$1" ]; then
        read -p "Copy directory recursively? " -n 1 -r
        if [ "$REPLY" == "y" ]; then
            arg="$arg -r"
        fi
        echo
    fi
    /usr/bin/cp $arg "$@"
}

Це просто дешевий CP-обгортку. Він завжди зберігає всі метадані (тобто, копіює час зміни файлів, належним чином копіює символьні посилання тощо), і якщо ви намагаєтесь скопіювати каталог, він запитує, чи слід його копіювати (рекурсивно).

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