
Я пытаюсь написать скрипт для рекурсивного копирования файлов из определенной папки, кроме files A.extn
, B/*.extn
и C/*
где B
и C
являются каталогами, а extn
это просто некоторое общее расширение. Вот что у меня есть:
#!/usr/local/bin/zsh
setopt EXTENDED_GLOB
TMPDIR=/tmp/test
cp -pR $(dirname $0)/**~(*.foo/*|*/bar.txt|*.abc|qux.txt) $TMPDIR
Однако это не делает отрицания шаблона, как ожидалось. Я думаю, я знаю, почему — хотя шаблон правильный (как видно по echo
), cp -R
не знает о шаблоне и входит в каталог, в который ему «не положено», и, попав туда, шаблон больше недействителен.
Как мне изменить вышесказанное, чтобы сделать то, что я хочу? Я думаю, это возможно с помощью find
и xargs
, но меня привлекает ясность вышесказанного, и я бы предпочел что-то похожее (но если это неправильный способ сделать это, я был бы полностью доволен другим решением).
решение1
Вы правы, шаблон раскрывается перед cp
запуском, поэтому он неизвестен этой команде.
Вы можете добиться желаемого, используя --parents
опцию to cp
вместо -R
. Это позволит скопировать только файлы, соответствующие вашему шаблону, но будет использовать полное имя пути, а не только конечное имя файла.
Но эта опция непереносима. Насколько мне известно, она поддерживается только GNU-версией cp.
решение2
Ваш шаблон может исключать файлы, которые вы не хотите копировать, но он не исключает каталоги, содержащие их, и вы сказали cp
копировать рекурсивно. Так что файлы копируются в любом случае. Хуже того, если у вас есть исходное дерево типа
foo
foo/bar.txt
hello
hello/world
hello/world/wibble.txt
затем шаблон расширяется, foo hello hello/world hello/world/wibble.txt
и в итоге вы получаете следующие файлы $TMPDIR
:
foo
foo/bar.txt
hello
hello/world
hello/world/wibble.txt
wibble.txt
world
world/wibble.txt
Это не имеет ничего общего с тем, что шаблон «больше не действителен». Шаблон расширяется оболочкой, cp
видит только список файлов.
Вам необходимо использовать инструмент копирования, который может исключать файлы при выполнении рекурсивного обхода.
Для этого можно использовать zcp, но он не будет копировать каталоги и не будет автоматически создавать целевые каталоги. Самый простой инструмент для этой работы — rsync. Pax — еще один вариант.
rsync -a --exclude='*.foo/*' --exclude='bar.txt' --exclude='*.abc' --exclude='/qux.txt' $(dirname $0) $TMPDIR