PQ
PQ.Hosting

Валюта

Команда cp в Linux: копирование файлов и папок с сохранением прав и метаданных

Автор
PQ
05 марта 2026
5 мин чтения
43 просмотров

cp знают все. Но используют в основном один вариант — и каждый раз гуглят когда нужно что-то нестандартное. Скопировать папку сохранив симлинки, показать прогресс копирования большого файла, не затереть более новую версию — всё это cp умеет, просто нужно знать правильные флаги.

Основы: файл, папка, маска

Скопировать файл в директорию:

cp file.txt /path/to/folder/

Скопировать и сразу переименовать:

cp file.txt /path/to/folder/newname.txt

Несколько файлов за один вызов:

cp file1.txt file2.txt file3.txt /path/to/folder/

По маске — все .log файлы в текущей директории:

cp *.log /var/backup/logs/

Директории: -r и ловушка с существующей целью

Без флага -r попытка скопировать папку даст omitting directory. Рекурсивное копирование:

cp -r /var/www/mysite /var/backup/mysite

Здесь есть нюанс который часто удивляет. Если /var/backup/mysite уже существует — папка скопируется внутрь и получится /var/backup/mysite/mysite. Если не существует — создастся с нужным именем. Это поведение не меняется флагами, нужно учитывать при написании скриптов.

Сохранить метаданные: -p и -a

Обычный cp создаёт новый файл с текущей датой и правами из umask. Для резервных копий это проблема — теряются оригинальные временны́е метки и владелец.

Флаг -p сохраняет: режим доступа, владельца, группу, временны́е метки:

cp -rp /etc/nginx /backup/nginx

Флаг -a (archive) — ещё полнее: включает -r, -p, и дополнительно сохраняет символические ссылки как ссылки, а не разворачивает их:

cp -a /var/www/mysite /backup/mysite

Для большинства сценариев резервного копирования -a предпочтительнее -rp.

Не затирать и спрашивать: -n, -i, -u

Три флага с похожим назначением, но разным поведением.

-n (no-clobber) — молча пропустить если файл уже есть:

cp -n source.txt /target/

-i (interactive) — спросить перед заменой:

cp -i file.txt /target/

-u (update) — скопировать только если источник новее чем существующий файл в цели, или если в цели его вообще нет:

cp -u /var/www/html/*.php /backup/html/

-u — это грубый инструмент синхронизации. Он не удаляет файлы которые исчезли из источника — только добавляет и обновляет.

Прогресс-бар для больших файлов

cp не показывает прогресс — просто молчит до конца. Для копирования файлов в несколько гигабайт это неудобно. Решение — пайп через pv (pipe viewer):

Установить pv если не установлен:

sudo apt-get install pv

Скопировать с прогресс-баром:

pv /source/large_file.iso > /target/large_file.iso

Для директорий — через tar:

tar cf - /source/folder | pv | tar xf - -C /target/

Вывод покажет скорость, объём переданного и примерное время до конца.

Файлы с пробелами в имени

Имя файла с пробелами без кавычек сломает команду — bash разобьёт его на несколько аргументов.

Использовать кавычки:

cp "my file with spaces.txt" /target/

Или экранировать пробелы обратным слешем:

cp my\ file\ with\ spaces.txt /target/

При копировании через маску файлов с пробелами лучше использовать find с -exec:

find /source -name "*.txt" -exec cp {} /target/ \;

Мгновенное копирование на btrfs и xfs: --reflink

На файловых системах btrfs и xfs есть механизм copy-on-write. Флаг --reflink=auto создаёт «виртуальную» копию мгновенно, без реального дублирования данных — место на диске тратится только когда файл начинают изменять:

cp --reflink=auto large_database.sql /backup/large_database.sql

Копирование файла в 10 ГБ занимает миллисекунды. На ext4 флаг игнорируется и cp работает обычным образом — auto означает «использовать если поддерживается».

Ротация бэкапов с датой

Копировать конфиг с датой в имени перед каждой правкой — хорошая привычка:

cp /etc/nginx/nginx.conf /etc/nginx/nginx.conf.$(date +%Y%m%d_%H%M%S)

Получится: nginx.conf.20260305_142233. Можно видеть когда был сделан каждый бэкап.

Автоматически удалять копии старше 30 дней:

find /etc/nginx -name "nginx.conf.*" -mtime +30 -delete

Копирование только определённых типов файлов рекурсивно

cp не умеет фильтровать по расширению рекурсивно — только *.ext в текущей директории. Для рекурсивной фильтрации нужен find:

Скопировать все .php файлы сохраняя структуру директорий:

find /var/www/html -name "*.php" -exec cp --parents {} /backup/ \;

--parents воспроизводит путь к файлу в целевой директории.

Когда cp недостаточно: rsync

Для регулярной синхронизации cp проигрывает rsync. Тот умеет копировать только изменившиеся блоки, работать по SSH, исключать по маске и удалять из цели то чего уже нет в источнике.

Синхронизировать директорию:

rsync -av --delete /var/www/html/ /backup/html/

Скопировать на удалённый сервер:

rsync -avz /var/www/html/ user@192.168.0.10:/backup/html/

Слеш после источника важен: с ним копируется содержимое, без него — сама папка внутрь целевой.

Шпаргалка

Задача Команда
Скопировать файл cp file.txt /target/
Скопировать и переименовать cp file.txt /target/newname.txt
Скопировать директорию (все метаданные) cp -a /source/ /target/
Не перезаписывать существующее cp -n file.txt /target/
Спрашивать перед заменой cp -i file.txt /target/
Только новые/изменённые cp -u /source/*.php /target/
С прогресс-баром pv source.iso > /target/source.iso
Файл с пробелами в имени cp "my file.txt" /target/
Мгновенно на btrfs/xfs cp --reflink=auto file /target/
Бэкап с датой cp file.conf file.conf.$(date +%Y%m%d)
Рекурсивно по расширению find /src -name "*.php" -exec cp --parents {} /dst/ \;
С выводом прогресса cp -rv /source/ /target/

Поделиться статьей

Похожие статьи