У меня проблема с копированием многих файлов в разные каталоги. Позвольте мне объяснить лучше:
Допустим, у меня в каталоге есть следующее:
$ ls
file1 file2 file3 file4 file5 dir1 dir2 dir3
и я хочу скопировать каждый файл* в каждом каталоге* одной командой. Я пробовал с:
echo dir{1..3} | xargs cp file{1..5} '{}' \;
Я намеревался сказать xargs обработать каждый dir* из echo и скопировать все файлы в обработанном вводе, но это и подобное не сработало. Я хотел бы избежать использования скрипта, потому что это задача, которую мне нужно повторить примерно для 20 каталогов, а имена файлов немного отличаются, поэтому я бы предпочел изменить команду, а не скрипт.
решение1
echo dir[1-3] | xargs -r -n1 cp file[1-5]
решение2
Вы делаете небольшую ошибку в использовании xargs. Без параметра -n xargs добавляет все параметры во входных данных к команде и echo dir{1..3}
не добавляет необходимый возврат каретки между каждой записью, поэтому xargs будет рассматривать результат как один параметр.
У xargs есть опция -n, которая может ограничить количество записей, и вам необходимо перечислить каталоги с \n или \0 в качестве разделителя:
find . -mindepth 1 -maxdepth 1 -type d -print0 | xargs -0 -n 1 cp file{1..5}
Команда find будет искать все каталоги в текущем каталоге и использовать \0 в качестве разделителя (что работает лучше, если у вас есть каталоги с пробелами), а xargs использует \0 в качестве разделителя и запускает команду каждый раз только с одним параметром.
решение3
Что-то вроде следующего должно сработать, если у них действительно есть такие имена:
#!/bin/bash
shopt -s nullglob
for dir in dir*/; do
cp file* "$dir"
done
Если вы хотите скопировать все файлы во все каталоги независимо от имени:
#!/bin/bash
shopt -s nullglob dotglob
for dir in */; do
for file in *; do
[[ -f $file ]] && cp "$file" "$dir"
done
done
решение4
Вы почти у цели. Вам нужно запустить отдельную cp
команду для каждого целевого каталога, потому что cp
создает только одну копию каждого исходного файла. Основная цель xargs
— запустить одну команду для нескольких аргументов, но вы можете указать ей передавать по одному элементу за раз с помощью параметра -n
. Также {} ;
есть синтаксис find … -exec
; вам не нужно (и вы не можете использовать) его с xargs
.
echo dir{1..3} | xargs -n 1 cp file{1..5}
Обратите внимание, что это работает только в том случае, если имена ваших каталогов не содержат пробелов или любых символов \'"
, поскольку xargs
нет способа определить, что эти символы являются частью имен файлов, а не кавычками и разделителями входных файлов. Альтернативный метод, не имеющий таких проблем, — использовать цикл оболочки:
for d in dirs{1..3}; do
cp file{1..5} "$d"
done
Все это предполагает, что вы можете легко различать файлы и каталоги по их именам. Если вы не можете, вы можете сопоставить каталоги, добавив /
в конце; например, */
сопоставляет все каталоги в текущих каталогах, foo[0-9]*/
сопоставляет все каталоги, имя которых начинается с foo
и цифры и т. д. В большинстве оболочек нет похожего способа сопоставить только некаталоги, но если вы передаете каталоги без cp
аргумента, чтобы указать ему сделать рекурсивную копию, каталоги игнорируются с сообщением об ошибке.
for d in */; do
cp * "$d"
done
В zsh вы можете использоватьквалификаторы globдля сопоставления только определенных типов файлов.
for d in *(/); do
cp *(.) $d
done