Как скопировать файл в несколько каталогов с помощью команды gnu cp

210

Можно ли скопировать один файл в несколько каталогов с помощью команды cp?

Я попробовал следующее, которое не сработало:

cp file1 /foo/ /bar/
cp file1 {/foo/,/bar}

Я знаю, что можно использовать цикл for или найти. Но возможно ли использовать команду gnu cp?

Том Файнер
источник

Ответы:

106

Нет, cpможет копировать несколько источников, но будет копировать только в один пункт назначения. Вы должны договориться о вызове cpнесколько раз - один раз в пункт назначения - для того, что вы хотите сделать; используя, как вы говорите, цикл или другой инструмент.

Лунная тень
источник
Спасибо за ответ! Теперь, когда я подумаю об этом немного больше, без дополнительных флагов (которых не существует), cp не будет знать, что является источником, и что такое каталог DEST.
Том Фейнер,
10
Это не правильный ответ. Пожалуйста, посмотрите ответ Роберта Гэмбла.
PlagueHammer
23
@Nocturne: какая часть из того, что я сказал, неверна? Роберт приводит пример использования другого инструмента для многократного вызова cp, как я предлагаю. Есть много возможных решений, которые предполагают использование других инструментов или конструкций для этого, но ОП действительно указал, что он уже знал, что это возможно.
лунная тень
2
К сожалению, было бы здорово, чтобы cp (и scp) поддерживали эту функцию. Тем не менее, мы можем использовать тройник, чтобы сделать раскол. superuser.com/questions/32630/…
Симон
4
@moonshadow: Конечно, ваш ответ правильный. Я думаю, что PlagueHammer хочет сказать, что в этом контексте другой ответ более полезен. Возможно, вы тоже можете включить что-то подобное в свой ответ?
Мирное
585

Вы не можете сделать это в cpодиночку, но вы можете комбинировать cpс xargs:

echo dir1 dir2 dir3 | xargs -n 1 cp file1

Будет ли копировать file1в dir1, dir2и dir3. xargsпозвоню cp3 раза, чтобы узнать xargsподробности.

Роберт Гэмбл
источник
3
Более подробная информация о xargs: cyberciti.biz/faq/…
Крис Бир
24
@ Симон как так? «Вы не можете сделать это в cpодиночку». Тот факт, что ответ был полезен, предлагая другой способ, не означает, что на вопрос не было ответа.
Николь
3
@NickC Аскер указал: «Я знаю, что возможно использовать цикл for или найти. Но возможно ли это с помощью команды gnu cp?» Хороший ответ - тот, который принят.
Саймон
25
Предусматривать, что ответы будут приниматься в зависимости от того, будут ли они технически отвечать на вопрос, было бы невыносимо педантично и не очень полезно.
нарды
4
Очень полезно! Для других новичков, таких как я: вы не можете использовать регулярные выражения с cp, но вы можете в первой части этой команды (например echo dir[1-3] | xargs -n 1 cp filename).
Джейсон
77

Подстановочные знаки также работают с кодом Робертса

echo ./fs*/* | xargs -n 1 cp test 
Павел
источник
и весь комментарий ... Например, чтобы переместить файл с правами root (фактически символическую ссылку), который был на моем рабочем столе, на рабочий стол всех пользователей, я сначала должен был выполнить sudo su (иначе не работало), а затем использовал: echo / home / * / Рабочий стол / | xargs -n 1 cp -av / home / myusername / Desktop / file.
Дэвид Г
19

Насколько я вижу, вы можете использовать следующее:

ls | xargs -n 1 cp -i file.dat

-iВариант cpкоманды означает , что вам будет предложено ли перезаписать файл в текущем каталоге с file.dat. Хотя это не полностью автоматическое решение, оно сработало для меня.

Евгений
источник
1
Хотя хорошо бы добавить -iохрану, разве это не побудит вас переписать каждый файл? а не копировать в каталоги?
Ежик
1
@Hedgehog Ну, я думаю, что эта команда полезна, когда в каталоге есть файл, и кто-то хочет скопировать его в подкаталоги каталога. В этом случае файл может быть перезаписан только один раз. Спасибо за ваш вопрос!
Евгений
2
Для меня это напечатало ряд cp: overwriteвопросов, но мне не нужно было отвечать ни на один из них, и это не переписывало файлы.
Евгений Сергеев
Также напечатал серию вопросов + скопировал в файл с именем dir с символом ':' в конце, никакого рабочего решения вообще, решение Пола работает отлично
jgpATs2w
19

Я бы использовал catи teeосновываясь на ответах, которые я видел по адресу /superuser/32630/parallel-file-copy-from-single-source-to-multiple-targets вместо cp.

Например:

cat inputfile | tee outfile1 outfile2 > /dev/null
deterb
источник
1
Беглый тест, который я только что выполнил, показывает, что он лучше всего работает, если в качестве места назначения используются разные физические диски (с двумя физическими копиями файловой базы, такой как исходное видео для цифрового фильма).
любопытнее
1
Если вы используете bash 3.0 или выше, вы можете использовать диапазоны следующим образом:cat <inputfile> | tee /path-to-files/outfile{1..4} > /dev/null
Самуил
tee < inputfile outfile1 outfile2 > /dev/nullЭто также полезная модель, как показывает ответ Taywee. Обратите внимание на использование io-redirection с '<', так что пайпинг от cat не нужен.
Алекс Телон
10

Эти ответы кажутся более сложными, чем очевидные:

for i in /foo /bar; do cp "$file1" "$i"; done
Waxrat
источник
элегантный и рабочий, чтобы сделать это для всех каталогов в текущем каталоге, можно использоватьfor d in */ ; do cp $file "$i" done
FantomX1
9

ls -db di*/subdir | xargs -n 1 cp File

-bесли в имени каталога есть пробел, иначе он будет разбит на xargs как другой элемент, если возникла эта проблема с версией echo

thAAAnos
источник
6

Не использую cp как таковую, но ...

Это пришло мне в голову в контексте копирования большого количества видеороликов Gopro с (медленной) SD-карты на три (медленных) USB-накопителя. Я хотел прочитать данные только один раз, потому что это заняло вечность. И я хотел, чтобы это было рекурсивно.

$ tar cf - src | tee >( cd dest1 ; tar xf - ) >( cd dest2 ; tar xf - ) | ( cd dest3 ; tar xf - )

(И вы можете добавить больше таких разделов> (), если хотите больше выходов.)

Я не проверял это, но это определенно намного быстрее, чем cp-in-a-loop (или несколько параллельных вызовов cp).

oggust
источник
5

Чтобы использовать копирование xargsв каталоги с использованием подстановочных знаков в Mac OS, единственное решение, которое мне помогло с пробелами в имени каталога:

find ./fs*/* -type d -print0 | xargs -0 -n 1 cp test 

Где testнаходится файл для копирования
и ./fs*/*каталоги для копирования

Проблема в том, что xargs видит пробелы в качестве нового аргумента, решения по изменению символа разделителя с использованием -dили -E, к сожалению, не работает должным образом в Mac OS.

MegaCookie
источник
4

Если вы хотите сделать это без разветвленной команды:

tee <inputfile file2 file3 file4 ... >/dev/null

Taywee
источник
2

По существу эквивалентен ответу xargs, но в случае, если вы хотите параллельное выполнение:

parallel -q cp file1 ::: /foo/ /bar/

Так, например, чтобы скопировать file1 во все подкаталоги текущей папки (включая рекурсию):

parallel -q cp file1 ::: `find -mindepth 1 -type d`

NB. Это, вероятно, сообщает о каких-либо заметных приростах скорости для очень конкретных случаев использования, например, если каждый целевой каталог представляет собой отдельный диск.

Он также функционально аналогичен аргументу '-P' для xargs.

alainv
источник
0

Нет, ты не можешь.

Я неоднократно обнаруживал, что могу использовать эту функцию, поэтому я сделал свой собственный инструмент, чтобы сделать это для меня.

http://github.com/ddavison/branch

довольно просто -
branch myfile dir1 dir2 dir3

ddavison
источник
Часто бывают сценарии, когда я пишу свой собственный такой сценарий, но в настоящее время я использую так много машин, что синхронизация их всех кажется большой проблемой. Если бы только был способ смонтировать облачный веб-каталог, /eнапример, по одному разу на каждой машине, то я мог бы написать свои собственные инструменты и хранить их навсегда.
Евгений Сергеев
0
ls -d */ | xargs -iA cp file.txt A
Си Ли
источник
1
Как насчет небольшого объяснения?
минут
Это на самом деле работает, но объяснение было бы здорово
Declex
0

Предположим, вы хотите скопировать fileName.txtвсе подкаталоги в текущем рабочем каталоге.

  1. Получить все имена подкаталогов lsи сохранить их во временный файл, скажем,allFolders.txt

    ls > allFolders.txt
  2. Распечатайте список и передайте его команде xargs.

    cat allFolders.txt | xargs -n 1 cp fileName.txt
Девендра Латту
источник
0

Другой способ - использовать кошку и тройник следующим образом:

cat <source file> | tee <destination file 1> | tee <destination file 2> [...] > <last destination file>

Я думаю, что это будет довольно неэффективно, поскольку задание будет разделено на несколько процессов (по одному на место назначения), и жесткий диск будет записывать несколько файлов одновременно в разные части диска. Однако, если вы хотите записать файл на несколько разных дисков, этот метод, вероятно, будет довольно эффективным (так как все копии могут происходить одновременно).

jww
источник
0

Использование bash-скрипта

DESTINATIONPATH[0]="xxx/yyy"
DESTINATIONPATH[1]="aaa/bbb"
                ..
DESTINATIONPATH[5]="MainLine/USER"
NumberOfDestinations=6

for (( i=0; i<NumberOfDestinations; i++))
    do
        cp  SourcePath/fileName.ext ${DESTINATIONPATH[$i]}

    done
exit
Патрик Мэнли
источник
Я дал этому отрицательный голос. Вопрос специально задан для решения без петель.
Алекс Телон
-1

если вы хотите скопировать несколько папок в несколько папок, можно сделать что-то вроде этого:

echo dir1 dir2 dir3 | xargs -n 1 cp -r / path / toyourdir / {subdir1, subdir2, subdir3}

Исаак
источник
-1

Если все ваши целевые каталоги соответствуют выражению пути - как они все подкаталоги path/to- тогда просто используйте findв комбинации с cpэтим:

find ./path/to/* -type d -exec cp [file name] {} \;

Вот и все.

Mig82
источник
Я дал этому отрицательный голос. Вопрос специально задан для решения не найти.
Алекс Телон
Спасибо за то, что вы так тщательно @AlexTelon. Я думаю, что пропустил этот бит. Я надеюсь, что вы были последовательны и проголосовали против каждого другого ответа, используя findв теме.
Mig82
-2

Если вам нужно конкретно указать, в какие папки копировать файл, вы можете объединить find с одним или несколькими greps. Например, чтобы заменить любые вхождения favicon.ico в любой подпапке, которую вы можете использовать:

find . | grep favicon\.ico | xargs -n 1 cp -f /root/favicon.ico
Kristofer
источник
-3

Это скопирует в непосредственные подкаталоги, если вы хотите пойти глубже, настройте -maxdepthпараметр.

find . -mindepth 1 -maxdepth 1 -type d| xargs -n 1 cp -i index.html

Если вы не хотите копировать во все каталоги, надеюсь, вы можете отфильтровать каталоги, которые вам не интересны. Пример копирования во все папки, начиная с a

find . -mindepth 1 -maxdepth 1 -type d| grep \/a |xargs -n 1 cp -i index.html

При копировании в произвольный / непересекающийся набор каталогов вам понадобится предложение Роберта Гэмбла.

еж
источник
-3

Мне нравится копировать файл в несколько каталогов как таковой: cp file1 /foo/; cp file1 /bar/; cp file1 /foo2/; cp file1 /bar2/ И копировать каталог в другие каталоги: cp -r dir1/ /foo/; cp -r dir1/ /bar/; cp -r dir1/ /foo2/; cp -r dir1/ /bar2/

Я знаю, что это похоже на ввод нескольких команд, но это хорошо работает для меня, когда я хочу набрать 1 строку и уйти на некоторое время.

Стас Фауске
источник
7
Вы отвечаете на 6-летний вопрос с 15 другими ответами. Ваш ответ должен быть довольно новым. Мое мнение - это не так.
Крейг С. Андерсон
-4

Например, если вы находитесь в родительском каталоге ваших папок назначения, вы можете сделать:

для я в $ (лс); сделать cp sourcefile $ i; сделано

Behrooz
источник
Вопрос говорит, что это возможно с помощью цикла for, так что это действительно ничего не добавляет.
LJNielsenDk
Downvoted. Никогда не пытайтесь анализировать выходные данныеls и всегда заключайте в кавычки переменные. for i in ./*; do cp sourcefile "$i"; done
sleblanc