Изменение шаблонов подстановки zsh для использования с cp

Изменение шаблонов подстановки zsh для использования с cp

Я пытаюсь написать скрипт для рекурсивного копирования файлов из определенной папки, кроме 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

Связанный контент