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

12

Этот вопрос является продолжением своего раннего вопроса « Создание многочисленных каталогов с помощью»mkdir .

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

mkdir $(printf "s%02i " $(seq 1 50))

который дополняет вторую цифру нулями. То есть каталоги , которые я получаю имеют вид s01, s02, ..., s49, s50.

Теперь я хотел бы использовать cpдля копирования одного файла (например, test.txt) в каждую из пятидесяти каталогов. Можно ли сделать это способом, аналогичным описанному выше? Например, будет ли работать следующее? Я относительно новичок в Unix / Linux, поэтому я не хочу пробовать это, пока кто-нибудь, пожалуйста, не даст мне указание, что это безопасно.

cp test.txt $ (printf "s% 02i.txt" $ (seq 1 50))

Если посмотреть на manстраницу cp, то не похоже, что она cpподдерживает несколько направлений:

NAME
       cp - copy files and directories

SYNOPSIS
       cp [OPTION]... [-T] SOURCE DEST
       cp [OPTION]... SOURCE... DIRECTORY
       cp [OPTION]... -t DIRECTORY SOURCE...

DESCRIPTION
       Copy SOURCE to DEST, or multiple SOURCE(s) to DIRECTORY.

       Mandatory  arguments  to  long  options are mandatory for short options
       too.
Андрей
источник

Ответы:

7

Если вы хотите использовать вывод своей команды для копирования файла в каждый каталог, используя его cp, вы всегда можете передать его по следующему адресу xargs:

printf "s%02i " $(seq 1 50) | xargs -n 1 cp test.txt

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

В качестве альтернативы, если каталоги уже существуют, вы можете попробовать что-то вроде:

find . -maxdepth 1 -type d -name 's[0-9][0-9]' -print0 | xargs -0 -I {} cp test.txt {}

или без трубы:

find . -maxdepth 1 -type d -name 's[0-9][0-9]' -exec cp test.txt {} \;

Последние две команды найдут любые файлы в текущем каталоге и cp test.txtк ним. -maxdepth 1Вариант позволит избежать каких - либо подкаталогов получения файла , а также. Имейте в виду , что 's[0-9][0-9]'сопоставление с sпоследующими любыми двумя цифрами означает, что, если по какой-либо причине у вас есть s99в cwd, он также получит копию test.txt.

tojrobinson
источник
8

Вы также можете позволить оболочке выполнять итерации с помощью forцикла. Это самый простой способ, который не зависит от внешних инструментов, таких как parallelили xargs, и я считаю, что его проще всего понять:

for name in $(printf "s%02i " $(seq 1 50)); do
    mkdir $name
    cp test.txt $name
done

Есть миллион других способов написать это, например:

for name in $(seq -w 1 50); do
    mkdir s$name
    cp test.txt s$name
done

Если вы хотите проверить, что должно быть выполнено, прежде чем делать это, вы можете сделать что-то вроде добавления команд с помощью команды echo, которая напечатает строку, а не выполнит ее:

for name in $(seq -w 1 50); do
    echo mkdir s$name
    echo cp test.txt s$name
done

выходы:

mkdir s01
cp test.txt s01
mkdir s02
cp test.txt s02
mkdir s03
cp test.txt s03
# etc.
Джим Пэрис
источник
2

Вы также можете использовать GNU параллельно . Предполагая, что вы находитесь в каталоге, содержащем text.txt, а ваши 50 папок находятся в /my/50dirs/path(например /my/50dirs/path/s01, и /my/50dirs/path/s02т. Д.), Вы должны выполнить:

seq -w 01 50 | parallel -j1 cp text.txt /my/50dirs/path/s{}
оборота don_crissti
источник
2
Лучше сделать это parallel -j1, иначе будет одно задание на ядро, и на многоядерном компьютере задания будут конкурировать за IO.
Жиль "ТАК - перестань быть злым"