
Вопрос:Мне нужен простой пример того, как использовать cp --no-target-directory
.
Я испытываю некоторые трудности в понимании cp --no-target-directory
. Я понимаюобъяснение дляmv --no-target-directory
, но я не могу себе представить, как его можно использовать cp
.
Например, когда команда
mv /tmp/source /tmp/dest
выполняется успешно, нет гарантии, что она/tmp/source
была переименована в/tmp/dest
: она могла быть переименована в/tmp/dest/source
, если бы какой-то другой процесс создал/tmp/dest
каталог. Однако, если командаmv -T /tmp/source /tmp/dest
выполняется успешно, нет никаких сомнений, что/tmp/source was renamed to
/tmp/dest`. (источник)
решение1
По умолчанию cp
проверяет, является ли его последний аргумент существующим каталогом. Если это происходит, cp
создает ссылку внутри этого каталога с базовым именем источника. То есть, если задана команда
cp foo/bar wibble
если wibble
существует каталог, то cp
копирует источник в wibble/bar
. Если wibble
не существует, то cp
связывает источник с wibble
.
Если вы хотите быть уверены, что копия всегда wibble
, то вы можете указать опцию --no-target-directory
(псевдоним -T
). Таким образом, если cp
все пройдет успешно, вы можете быть уверены, что копия вызывается wibble
. Если wibble
уже существовал как каталог, то cp
произойдет сбой.
В табличной форме:
The target is … Without -T With -T
existing directory copy in the directory error
existing file (not dir) overwrite overwrite
does not exist create create
Единственное отличие в том, что с -T
, в случае, если целью является существующий каталог, команда возвращает ошибку. Это полезно, когда вы ожидаете, что каталог не существует: вы получаете сообщение об ошибке вместо чего-то непредсказуемого.
То же самое относится к mv
и ln
. Если целью является существующий каталог, с -T
, они сигнализируют об ошибке, а не молча делают что-то другое.
С cp
, есть другой случай. Если вы делаете рекурсивное копирование и источником является каталог, то cp -T
копирует содержимое источника в место назначения, а не копирует сам источник. То есть, учитывая
$ tree source destination
source
└── foo
destination
└── bar
затем
$ cp -rv source destination
`source' -> `destination/source'
`source/foo' -> `destination/source/foo'
тогда как
% cp -rvT source destination
`source/foo' -> `destination/foo'
решение2
Вы можете использовать его --no-target-directory
, если не хотите копировать исходный каталогподсуществующий целевой каталог, вы хотите скопировать исходный каталогнацелевой каталог.
Вот пример копирования каталога с и без --no-target-directory
:
$ mkdir a
$ touch a/b a/c
$ find
.
./a
./a/c
./a/b
$ cp -r a b # b does not exist; becomes copy of a
$ find
.
./b
./b/b
./b/c
./a
./a/c
./a/b
$ rm -r b
$ mkdir b
$ cp -r a b # b already exists; a is copied *underneath* it
$ find
.
./b
./b/a
./b/a/b
./b/a/c
./a
./a/c
./a/b
$ rm -r b
$ mkdir b
$ cp -r --no-target-directory a b # b already exists; becomes copy of a
$ find
.
./b
./b/b
./b/c
./a
./a/c
./a/b
Вы можете добиться того же эффекта, добавив к имени исходного каталога суффикс слеш-точка, /.
как в следующем примере: cp -r a/. b
скопирует исходный каталогa
на b
и непод b
.
Ни один из вышеперечисленных методов не является тем же самым, что сказать "копировать только содержимое исходного каталога в существующий целевой", поскольку, если вы попросите сохранить время и разрешения, существующий целевой каталог получит время и разрешения исходного каталога. Пример (отредактированный для удаления ненужной информации):
$ find . -ls
drwx------ Oct 13 13:31 ./b # note date and permissions
drwxr-xr-x Jan 1 2013 ./a # note date and permissions
-rw-r--r-- Oct 13 13:23 ./a/c
-rw-r--r-- Oct 13 13:23 ./a/b
$ cp -rp --no-target-directory a b # preserve mode and timestamps
$ find . -ls
drwxr-xr-x Jan 1 2013 ./b # note copied date and permissions
-rw-r--r-- Oct 13 13:23 ./b/b
-rw-r--r-- Oct 13 13:23 ./b/c
drwxr-xr-x Jan 1 2013 ./a
-rw-r--r-- Oct 13 13:23 ./a/c
-rw-r--r-- Oct 13 13:23 ./a/b
Копирование только содержимого не перенесет режим или временные метки исходного каталога в целевой каталог.
решение3
А как насчет следующего?
$ cp -rvT Dir_1 Dir_2
‘Dir_1/File_3.txt’ -> ‘Dir_2/File_3.txt’
‘Dir_1/File_1.txt’ -> ‘Dir_2/File_1.txt’
‘Dir_1/File_2.txt’ -> ‘Dir_2/File_2.txt’
$ cp -rv Dir_1 Dir_2
‘Dir_1’ -> ‘Dir_2/Dir_1’
‘Dir_1/File_3.txt’ -> ‘Dir_2/Dir_1/File_3.txt’
‘Dir_1/File_1.txt’ -> ‘Dir_2/Dir_1/File_1.txt’
‘Dir_1/File_2.txt’ -> ‘Dir_2/Dir_1/File_2.txt’
Таким образом, это просто другой способ записи cp Dir_1/* Dir_2/
. Однако он перехватывает скрытые файлы в корне Dir_1, которые были бы пропущены простым cp *
.
$ touch Dir_1/.Hidden_File_{1,2,3}.txt
$ cp -rv Dir_1/* Dir_2
cp: No match.
$ cp -rvT Dir_1 Dir_2
‘Dir_1/.Hidden_File_2.txt’ -> ‘Dir_2/.Hidden_File_2.txt’
‘Dir_1/.Hidden_File_3.txt’ -> ‘Dir_2/.Hidden_File_3.txt’
‘Dir_1/.Hidden_File_1.txt’ -> ‘Dir_2/.Hidden_File_1.txt’