[ Content | View menu ]

Рекурсивные операции с файлами в Linux

Опубликовано 16.06.2009

Иногда возникает путаница между опциями -r и -R, каждая из которых в разных программах может означать рекурсивную обработку файлов в найденных каталогах. А может означать нечто совершенно противоположное или работать не так, как этого ожидал пользователь. Попробуем разобраться, в каких случаях что используется.

Эпиграф

— Это новый «Гарри Поттер». Я заказал версии для детей и взрослых, чтобы проверить, что в тексте нет различий.
Морис Мосс, The IT Crowd.

chmod

Неправильно:

chmod -r 755 dir

Ключ -r у chmod интерпретируется как «запретить всем чтение файла», а 755 в данном случае рассматривается как название файла, у которого изменяются права. Поскольку в подавляющем большинстве случаев файла с таким названием в текущей директории отсутствует, то команда возвращает ошибку.

Правильно:

chmod -R 755 dir

chown, chattr, chgrp

Неправильно:

chown -r user:group dir
chattr -r dir +I
chgrp -r group dir

У вышеперечисленных команд опция -r просто отсутствует. Для рекурсивной обработки директорий необходимо использовать опцию -R. Очевидно, так сделано из солидарности с «братской» командой chmod

Правильно:

chown -R user:group dir. .
chgrp -R group dir
chattr -R dir # только Linux, только для ext2/ext3

cp

Неправильно:

cp -r dir destdir

Правильно:

cp -R dir destdir

Несмотря на то, что в странице документации cp из GNU coreutils сказано, что опции -r и -R равнозначны и означают рекурсивную обработку встречающихся директорий, опция -r, в отличие от -R, не соответствует стандарту POSIX и ее указание может повлечь за собой неожиданные последствия в случае, если очередной копируемый объект является чем-то отличным от обычного файла или директории (например, символической ссылкой, fifo или сокетом). В таких случаях некоторые реализации cp просто копируют содержимое ссылки/fifo, тогда как при -R такие объекты пересоздаются заново. Раньше такое поведение было присуще GNU cp, о чем до сих пор имеется свидетельство в русском man cp. Что касается более правильных (чем Linux) систем, то, например, в BSD-версии cp опция -r работает в «режиме совместимости», т.е. не создает символическую ссылку заново, а копирует содержимое в файл с тем же именем.

ls

Неправильно:

ls -r

Ключ -r команды ls означает «обратный порядок сортировки»
Правильно:

ls -R

rm, grep

Зато в следующих случаях употребление -r/-R равнозначно:

rm -r dir
rm -R dir

а также

grep -r pattern dir
grep -R pattern dir

Что касается grep, то, во-первых, обе опции не соответствуют POSIX (но, похоже, присутствуют во всех реализациях) Во-вторых, иногда возникает путаница между опциями -i (игнорировать регистр) и -I (пропускать двоичные файлы). Но это уже тема для другого разговора :)

Прочие команды

Поскольку команд, в том или ином виде поддерживающих рекурсивную обработку каталогов, набралось довольно много, то я попробовал свести их в одну таблицу.

команда -r -R
chacl рекурсия удаление ACL только с файлов
setfacl не поддерживается рекурсия
cvs номер ревизии рекурсия
diff рекурсия не поддерживается
gzip/gunzip рекурсия не поддерживается
zip рекурсия рекурсия, начиная с текущей директории (см. man zip, там есть существенная разница в обработке -r и -R)
rsync рекурсия использование относительных путей
wget рекурсия указывает список отвергаемых шаблонов

Заключение

Как видно, в большинстве случаев для указания рекурсии используется опция -r в нижнем регистре, в противовес стандартным утилитам, для которых характерно все же -R. Поэтому совет один: в случае сомнения смотрите в man, там все написано :)

Постскриптум

По абзацу про cp видно, что русская документация в некоторых дистрибутивах (не будем показывать пальцем на Debian и Ubuntu) не соответствует реальному положению дел. В частности, несмотря на то, что в jaunty используется GNU coreutis 6.10, русский man описывает cp версии 4.1. Желающие могут самостоятельно сравнить свою версию man 1 cp с локализованной. Другими словами, русская страница документации cp в силу своей древности вводит пользователя в заблуждение, т.е. врёт. По этой причине я рекомендую сделать apt-get remove manpages-ru.

«
»

2 комментария

Write a comment - TrackBack - RSS Comments

  1. Comment by anon:

    > По этой причине я рекомендую сделать apt-get remove manpages-ru

    Плюсую. Помню как потерял с час времени, из за феерично переведенного мана:

    RECV(2)

    If from is not NULL, and the underlying protocol provides the source address, this source address is filled in.

    Если параметр from не равен NULL, а сокет не является ориентированным на соединения, то адресотправителя в сообщении не заполняется.

    16.06.2009 @ 10:28
  2. Comment by anon:

    scp неплохо было бы упомянуть. Нигде проблем с -r/-R не испытывал, только в scp почему-то постоянно пишу -R.

    22.07.2009 @ 08:49
Write comment

Я не робот.