У меня есть несколько каталогов { dir1,dir2,dir3,dir4
} на компьютере с Linux.
В каждом каталоге есть несколько файлов (с одинаковым расширением, скажем, .zip), которые я хочу скопировать в соответствующие каталоги { dir1-bck,dir2-bck,dir3-bck,dir4-bck
}. Мне не нужно копировать всю папку, а только несколько файлов в каждой.
Как бы мне сделать так, чтобы файлы были скопированы из dir1/*.zip
... dir1-bck
для списка предоставленных каталогов. В настоящее время я использую:
cp -r src/dir1/*.zip dest/dir1-bck/
cp -r src/dir2/*.zip dest/dir2-bck/
cp -r src/dir3/*.zip dest/dir3-bck/
cp -r src/dir4/*.zip dest/dir4-bck/
Это работает, но есть огромный потенциал для улучшения.
Просматривая xargs
страницу руководства и похожие сообщения на форуме, я чувствую, что это инструмент для этой работы, но, похоже, я не могу в нем разобраться.
решение1
Вероятно, for
цикл будет как раз правильным. Точная форма зависит от того, как названы эти каталоги. Это может быть:
cd src || exit 1
for d in "dir"{1..4}; do
cp -r "$d"/*.zip "../dest/$d-bck/"
done
Примечания:
- Хорошо работать изнутри
src
(cd src
), так что переменная содержит строку, которую можно использовать в целевом пути без дополнительной обработки. Целевой путь был скорректирован путем добавления препина../
в этом случае, но в целом он может быть таким, как"/full/path/to/dest/$d-bck/"
. - Я цитировал
dir
на случай, если вы замените имя пробелами или чем-то подобным. Я заключил в двойные кавычки$d
по той же причине иболее. - Если
*.zip
это файлы, то вам не нужны-r
.
Альтернативно for
строка может быть такой:
for d in dir1 dir2 dir3 dir4; do
что было бы полезно, если вам нужно указать несколько произвольно названных каталогов. Или даже:
for d in *; do
Можно сделать несколько улучшений, например:
( cd src || exit 1
for d in *; do
dst="../dest/$d-bck/"
[ -d "$d" ] && mkdir -p "$dst" && cp -- "$d"/*.zip "$dst"
done )
Улучшения:
- Весь код выполняется в подоболочке (
(…)
), поэтомуcd
не повлияет на текущую оболочку, даже если вы вставите код в терминал. Если бы это был автономный скрипт (выполняемый, а не исходный), то подоболочка была бы неактуальна. - Проверяем,
$d
является ли это каталогом. - Мы пытаемся создать целевой каталог (на случай, если он не существует).
- Мы продолжим работу
cp
только в том случае, если целевой каталог существует. - Мы используемдвойное тирев случае, если
$d
начинается с тире.
Возможные проблемы:
"$d"/*.zip
может расшириться до слишком большого количества элементов (Argument list too long
). Ваши исходные команды "неполны" таким же образом. Если в каждом каталоге "всего несколько файлов", то это не должно быть проблемой."$d"/*.zip
может не расширяться (*
остается буквальным). Это не должно навредить, но целевой каталог будет создан заранее. В таком случае может потребоваться дополнительная логика для подавления создания каталога.- Статус выхода всего фрагмента зависит только от последнего
[ … && mkdir … && cp …
. Вам нужна дополнительная логика, чтобы более ранние проблемы влияли на статус выхода.