Skopiuj folder rekurencyjnie, z wyłączeniem niektórych folderów
197
Próbuję napisać prosty skrypt bash, który skopiuje całą zawartość folderu, w tym ukryte pliki i foldery, do innego folderu, ale chcę wykluczyć niektóre określone foldery. Jak mogłem to osiągnąć?
Wyobrażam sobie coś takiego. -nazwa * potokował do grep / v „exclude-pattern”, aby odfiltrować te, których nie chcesz, a następnie przesłał do cp, aby wykonać kopię.
i_am_jorf
1
Próbowałem zrobić coś takiego, ale nie mogłem wymyślić, jak używać cp z fajką
trobrock
1
To powinno prawdopodobnie przejść do superużytkownika. Polecenie, którego szukasz, to xargs. Możesz także zrobić coś takiego jak dwie smoły połączone rurą.
Kyle Butt,
1
Być może jest już późno i nie odpowiada dokładnie na pytanie, ale oto wskazówka: jeśli chcesz wykluczyć tylko bezpośrednie cp -R !(dir1|dir2) path/to/destination
potomki
1
Pamiętaj, że !(dir1|dir2)wzorzec wymaga extglobwłączenia ( shopt -s extglobaby go włączyć).
Pamiętaj, że używanie sourcei source/są różne. Końcowy ukośnik środki, aby skopiować zawartość folderu sourcedo destination. Bez końcowego ukośnika oznacza to skopiowanie folderusource do destination.
Alternatywnie, jeśli masz wiele katalogów (lub plików) do wykluczenia, możesz użyć --exclude-from=FILEgdzieFILE jest nazwa pliku zawierającego pliki lub katalogi do wykluczenia.
--exclude może również zawierać symbole wieloznaczne, takie jak --exclude=*/.svn*
Sugeruję dodanie opcji --dry-run, aby sprawdzić, które pliki zostaną skopiowane.
loretoparisi,
1
@AmokHuginnsson - Z jakich systemów korzystasz? Rsync jest domyślnie dołączony do wszystkich popularnych dystrybucji Linuksa, w tym RHEL, CentOS, Debian i Ubuntu, i wierzę, że jest również w FreeBSD.
siliconrockstar
1
W przypadku dystrybucji pochodzących z RHEL: yum install rsync, lub w wersjach opartych na Debianie: apt-get install rsync. To nie jest problem, chyba że budujesz swój serwer z absolutnej bazy na własnym sprzęcie. rsync jest domyślnie instalowany na moich urządzeniach Amazon EC2, a także na moich urządzeniach ZeroLag i RackSpace.
siliconrockstar
2
rsync wydaje się być bardzo wolny w porównaniu do cp? Przynajmniej takie było moje doświadczenie.
Kojo
2
Na przykład, aby zignorować git reż:rsync -av --exclude='.git/' ../old-repo/ .
nycynik
40
Użyj smoły razem z fajką.
cd /source_directory
tar cf ---exclude=dir_to_exclude .|(cd /destination && tar xvf -)
Takie podejście niepotrzebnie najpierw przetwarza źródło docelowe (i wyklucza określone katalogi w archiwum), a następnie rozdziela je w celu. Niepolecane!
Wouter Donders
4
@Waldheri się mylisz. To najlepsze rozwiązanie. Robi dokładnie to, czego zażądał OP i działa przy domyślnej instalacji większości systemów operacyjnych takich jak * nix. Tarowanie i odłączanie odbywa się w locie bez artefaktu systemu plików (w pamięci), koszt tego tar + untar jest znikomy.
AmokHuginnsson
@WouterDonders Tar to minimalny narzut. Nie stosuje kompresji.
Kyle Butt
9
Możesz używać findz tą -pruneopcją.
Przykład z man find:
cd / source-reż
odnaleźć . -nazwa .snapshot -prune -o \ (\! -name * ~ -print0 \) |
cpio -pmd0 / dest-reż
To polecenie kopiuje zawartość katalogu / source-dir do / dest-dir, ale pomija
pliki i katalogi o nazwie .snapshot (i wszystko w nich zawarte). To także
pomija pliki lub katalogi, których nazwa kończy się na ~, ale nie ich
namioty Konstrukcja -prune -o \ (... -print0 \) jest dość powszechna. The
Chodzi o to, że wyrażenie przed -prune pasuje do rzeczy, które są
być przycinanym. Jednak sama akcja -prune zwraca true, więc
następujące -o zapewnia, że oceniana jest tylko prawa strona
katalogi, które nie zostały przycięte (zawartość przycinanego
katalogi nie są nawet odwiedzane, więc ich zawartość nie ma znaczenia).
Wyrażenie po prawej stronie -o znajduje się tylko w nawiasach
dla jasności. Podkreśla, że akcja -print0 ma miejsce tylko
dla rzeczy, które nie miały zastosowania - przycinała je. Ponieważ
domyślny warunek `i 'między testami wiąże się mocniej niż -o, to
i tak jest ustawieniem domyślnym, ale nawiasy pomagają pokazać, co się dzieje
na.
Przepraszam, ale tak naprawdę nie rozumiem, dlaczego 5 osób zagłosowało za tym, gdy było to wprawdzie niesprawdzone i wydaje się, że nie działa na prostym teście: próbowałem tego w podkatalogu /usr/share/iconsi od razu dostałem, find: paths must precede expression: 22x22gdzie ten drugi jest jednym z podkatalogów . Moje polecenie brzmiało find . -name * -print0 | grep -v "scalable" | xargs -0 -I {} cp -a {} /z/test/(wprawdzie, jestem na MSYS2, więc naprawdę w /mingw64/share/icons/Adwaita, ale nie widzę, jak to wina MSYS2)
underscore_d
0
EXCLUDE="foo bar blah jah"
DEST=$1
for i in*dofor x in $EXCLUDE
doif[ $x != $i ];then
cp -a $i $DEST
fidonedone
To jest niepoprawne. Kilka problemów: Jak napisano, skopiuje plik, który nie powinien być wykluczony wiele razy (liczba elementów do wykluczenia, która w tym przypadku wynosi 4). Nawet jeśli spróbujesz skopiować „foo”, pierwszy element na liście wykluczeń, nadal zostanie on skopiowany, gdy dojdziesz do x = bar, a ja nadal jest foo. Jeśli nalegasz na zrobienie tego bez wcześniejszych narzędzi (np. Rsync), przenieś kopię do instrukcji if poza pętlę „for x in ...” i spraw, aby pętla „for x ...” zmieniła instrukcję logiczną w plik kopii (prawda). To powstrzyma Cię przed wielokrotnym kopiowaniem.
Eric Bringley,
0
zainspirowany odpowiedzią @ SteveLazaridis, która się nie powiedzie, oto funkcja powłoki POSIX - wystarczy skopiować i wkleić do pliku o nazwie cpxyout $PATHi uczynić go wykonywalnym ( chmod a+x cpr). [Źródło jest teraz utrzymywane w moim GitLab .
#!/bin/sh# usage: cpx [-n|--dry-run] "from_path" "to_path" "newline_separated_exclude_list"# limitations: only excludes from "from_path", not it's subdirectories
cpx(){# run in subshell to avoid collisions(_CopyWithExclude"$@")}_CopyWithExclude(){case"$1"in-n|--dry-run){DryRun='echo'; shift;};;esac
from="$1"
to="$2"
exclude="$3"
$DryRun mkdir -p "$to"if[-z "$exclude"];then
cp "$from""$to"returnfi
ls -A1 "$from" \
|while IFS= read -r f;do
unset excluded
if[-n "$exclude"];thenfor x in $(printf "$exclude");doif["$f"="$x"];then
excluded=1breakfidonefi
f="${f#$from/}"if[-z "$excluded"];then
$DryRun cp -R "$f""$to"else[-n "$DryRun"]&& echo "skip '$f'"fidone}# Do not execute if being sourced["${0#*cpx}"!="$0"]&& cpx "$@"
Nie wydaje się pomocne stwierdzenie, że czyjaś odpowiedź „nie powiedzie się” bez wyjaśnienia, co jest z nią nie tak i jak to naprawić ...
podkreślenie
@underscore_d: prawda, z perspektywy czasu, zwłaszcza, że nie pamiętam teraz, co się nie udało :-(
go2null
Wiele rzeczy: (1) kopiuje pliki wiele razy i (2) logika nadal kopiuje pliki do wykluczenia. Uruchom przez pętle za pomocą i = foo: zostanie skopiowany 3 razy zamiast 4 dla każdego innego pliku, np. I = test.txt.
Eric Bringley,
1
dzięki @EricBringley za wyjaśnienie braków odpowiedzi Steve'a. (Powiedział jednak, że to nie zostało przetestowane .)
cp -R !(dir1|dir2) path/to/destination
!(dir1|dir2)
wzorzec wymagaextglob
włączenia (shopt -s extglob
aby go włączyć).Odpowiedzi:
Użyj rsync:
Pamiętaj, że używanie
source
isource/
są różne. Końcowy ukośnik środki, aby skopiować zawartość folderusource
dodestination
. Bez końcowego ukośnika oznacza to skopiowanie folderusource
dodestination
.Alternatywnie, jeśli masz wiele katalogów (lub plików) do wykluczenia, możesz użyć
--exclude-from=FILE
gdzieFILE
jest nazwa pliku zawierającego pliki lub katalogi do wykluczenia.--exclude
może również zawierać symbole wieloznaczne, takie jak--exclude=*/.svn*
źródło
rsync -av --exclude='.git/' ../old-repo/ .
Użyj smoły razem z fajką.
Możesz nawet użyć tej techniki w ssh.
źródło
Możesz używać
find
z tą-prune
opcją.Przykład z
man find
:źródło
cpio
nie został jeszcze spakowany dla MSYS2.możesz użyć tar, z opcją --exclude, a następnie rozpakuj ją w miejscu docelowym. na przykład
zobacz stronę man tar, aby uzyskać więcej informacji
źródło
Podobne do pomysłu Jeffa (niesprawdzone):
źródło
/usr/share/icons
i od razu dostałem,find: paths must precede expression: 22x22
gdzie ten drugi jest jednym z podkatalogów . Moje polecenie brzmiałofind . -name * -print0 | grep -v "scalable" | xargs -0 -I {} cp -a {} /z/test/
(wprawdzie, jestem na MSYS2, więc naprawdę w/mingw64/share/icons/Adwaita
, ale nie widzę, jak to wina MSYS2)Nie przetestowano ...
źródło
zainspirowany odpowiedzią @ SteveLazaridis, która się nie powiedzie, oto funkcja powłoki POSIX - wystarczy skopiować i wkleić do pliku o nazwie
cpx
yout$PATH
i uczynić go wykonywalnym (chmod a+x cpr
). [Źródło jest teraz utrzymywane w moim GitLab .Przykładowe użycie
źródło