Bazı klasörler hariç klasörü tekrar tekrar kopyalama


197

Gizli dosyalar ve klasörler dahil bir klasörün tüm içeriğini başka bir klasöre kopyalayacak basit bir bash betiği yazmaya çalışıyorum, ancak belirli belirli klasörleri hariç tutmak istiyorum. Bunu nasıl başarabilirim?


1
Bulmak gibi bir şey hayal ediyorum. -name * istemediğiniz filtreleri filtrelemek için grep / v "exclude-pattern" e ve sonra kopyayı yapmak için cp'ye gönderilir.
i_am_jorf

1
Böyle bir şey yapmaya çalışıyordum, ama bir boru ile cp nasıl kullanılacağını
anlayamadım

1
Bu muhtemelen süper kullanıcıya gitmelidir. Aradığınız komut xargs. Bir boru ile birbirine bağlanmış iki katran gibi bir şey de yapabilirsiniz.
Kyle Butt

1
Belki de geç ve soruyu doğru cevaplamıyor ama burada bir ipucu: Eğer dizinin sadece yakın çocukları hariç tutmak istiyorsanız, bash desen eşleşmesinden faydalanabilirsiniz, örneğincp -R !(dir1|dir2) path/to/destination
Boris D. Teoharov

1
Desenin açılması !(dir1|dir2)gerektiğini unutmayın extglob( shopt -s extglobaçmak için).
Boris D. Teoharov

Yanıtlar:


335

Rsync kullanın:

rsync -av --exclude='path1/to/exclude' --exclude='path2/to/exclude' source destination

Kullanarak unutmayın sourceve source/farklıdır. Sondaki eğik çizgi, klasörün içeriğini sourceiçine kopyalamak anlamına gelir destination. Sondaki eğik çizgi olmadan, klasörü sourceiçine kopyalamak anlamına gelir destination.

Hariç tutmak dizinleri (veya dosya) bir sürü varsa Alternatif olarak, kullanabilirsiniz --exclude-from=FILEnerede, FILEdosya veya dışlamak için dizinleri içeren bir dosyanın adıdır.

--exclude ayrıca joker karakterler de içerebilir. --exclude=*/.svn*


10
Hangi dosyaların kopyalanacağını kontrol etmek için --dry-run eklemenizi öneririm.
loretoparisi

1
@AmokHuginnsson - Hangi sistemleri kullanıyorsunuz? Rsync, RHEL, CentOS, Debian ve Ubuntu da dahil olmak üzere bildiğim tüm ana Linux dağıtımlarında varsayılan olarak bulunur ve bunun FreeBSD'de de olduğuna inanıyorum.
siliconrockstar

1
RHEL'den türetilen dağıtımlar için: yum install rsync veya Debian tabanlı sürümlerde: apt-get install rsync. Sunucunuzu kendi donanımınıza mutlak tabandan kurmadıkça, bu bir sorun değildir. rsync, Amazon EC2 kutularıma ve ZeroLag ve RackSpace kutularıma varsayılan olarak yüklenir.
siliconrockstar

2
rsync cp ile karşılaştırıldığında son derece yavaş görünüyor? En azından bu benim deneyimimdi.
Kojo

2
Örneğin git dir görmezden gelmek için:rsync -av --exclude='.git/' ../old-repo/ .
nycynik

40

Bir boru ile birlikte katran kullanın.

cd /source_directory
tar cf - --exclude=dir_to_exclude . | (cd /destination && tar xvf - )

Bu tekniği ssh boyunca bile kullanabilirsiniz.


Bu yaklaşım gereksiz yere önce hedef kaynağı tartar (ve arşivdeki belirli dizinleri hariç tutar) ve daha sonra onu hedefte açar. Tavsiye edilmez!
Wouter Donders

4
@ Waldheri yanılıyorsunuz. Bu en iyi çözümdür. Tam olarak OP'nin istediği şeyi yapar ve * nix gibi OS'lerin çoğunun varsayılan yüklemesinde çalışır. Taring ve untaring, dosya sistemi artefaktı (bellekte) olmadan anında yapılır, bu tar + untar'ın maliyeti ihmal edilebilir.
AmokHuginnsson

@WouterDonders Tar minimum yükü vardır. Sıkıştırma uygulamıyor.
Kyle Butt

9

Sen kullanabilirsiniz findile-pruneSeçenek .

'Den bir örnek man find :

       cd / kaynak-yön
       bulmak. -name .snapshot -prune -o \ (\! -name * ~ -print0 \) |
       cpio -pmd0 / dest-dir

       Bu komut / source-dir içeriğini / dest-dir dizinine kopyalar, ancak atlar
       .snapshot (ve içindeki herhangi bir şey) adlı dosya ve dizinler. Ayrıca
       adı ~ ile biten ancak içeriği bitmeyen dosyaları veya dizinleri atlar
       Çadır. -Prune -o \ (... -print0 \) yapısı oldukça yaygındır. 
       buradaki fikir, - prune öncesi ifadenin,
       budanmak. Ancak, -prune eyleminin kendisi true değerini döndürür,
       aşağıdaki -o sağ tarafın yalnızca
       budama almayan dizinler (budama içeriği
       dizinler bile ziyaret edilmez, bu nedenle içerikleri önemsizdir).
       -O'nun sağ tarafındaki ifade yalnızca parantez içindedir
       açıklık için. -Print0 eyleminin yalnızca gerçekleştiğini vurgular
       - onlara erik uygulanmayan şeyler için. Çünkü
       Testler arasındaki varsayılan `ve 'koşulu -o'dan daha sıkı bağlanır, bu
       yine de varsayılan ayardır, ancak parantezler ne olup bittiğini göstermeye yardımcı olur
       üzerinde.

Doğrudan bir sayfadan yüksek düzeyde alakalı bir örnek bulma desteği.
David M

Gerçekten iyi görünüyor! Bu, çevrimiçi dokümanlarda da mevcuttur . Ne yazık ki cpiohenüz MSYS2 için paketlenmedi.
underscore_d

3

--exclude seçeneği ile tar öğesini kullanabilir ve ardından hedefte yıldız işareti kaldırabilirsiniz. Örneğin

cd /source_directory
tar cvf test.tar --exclude=dir_to_exclude *
mv test.tar /destination 
cd /destination  
tar xvf test.tar

daha fazla bilgi için katran'ın man sayfasına bakınız


2

Jeff'in fikrine benzer (denenmemiş):

find . -name * -print0 | grep -v "exclude" | xargs -0 -I {} cp -a {} destination/

Üzgünüm, ama 5 kişi neden itiraf edilmemiş ve basit bir test üzerinde çalışmıyor gibi görünüyordu neden anlamıyorum: Bir alt dizin denedim /usr/share/iconsve hemen find: paths must precede expression: 22x22orada alt dizinlerden biri nerede var . Benim komut oldu find . -name * -print0 | grep -v "scalable" | xargs -0 -I {} cp -a {} /z/test/(kuşkusuz, çok gerçekten de, MSYS2 çıkıyorum /mingw64/share/icons/Adwaitaama bu MSYS2 hatası olduğunu nasıl göremez)
underscore_d

0
EXCLUDE="foo bar blah jah"                                                                             
DEST=$1

for i in *
do
    for x in $EXCLUDE
    do  
        if [ $x != $i ]; then
            cp -a $i $DEST
        fi  
    done
done

Test edilmemiş ...


Bu yanlış. Birkaç sorun: Yazıldığı gibi, birden çok kez dışarıda bırakılmaması gereken bir dosyayı kopyalar (bu durumda 4 olan hariç tutulacak öğe sayısı). Hariç tutma listesindeki ilk öğe olan 'foo'yu kopyalamaya çalışsanız bile, x = çubuğuna ulaştığınızda yine de kopyalanacaktır ve i hala foo'dur. Önceden var olan araçlar (örneğin rsync) olmadan bunu yapmakta ısrar ediyorsanız, kopyayı 'for x in ...' döngüsünün dışındaki bir if ifadesine taşıyın ve 'for x ...' döngüsünün mantıksal ifadeyi değiştirmesini sağlayın. if (true) kopya dosyası. Bu, birden çok kez kopyalamanızı engeller.
Eric Bringley

0

@ SteveLazaridis'in başarısız olduğu cevabından esinlenerek, bir POSIX kabuk işlevi var - sadece cpxyout adlı bir dosyaya kopyalayıp yapıştırın $PATHve çalıştırılabilir ( chmod a+x cpr) yapın. [Kaynak artık GitLab'ımda korunuyor .

#!/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"
      return
  fi

  ls -A1 "$from" \
    | while IFS= read -r f; do
        unset excluded
        if [ -n "$exclude" ]; then
          for x in $(printf "$exclude"); do
          if [ "$f" = "$x" ]; then
              excluded=1
              break
          fi
          done
        fi
        f="${f#$from/}"
        if [ -z "$excluded" ]; then
          $DryRun cp -R "$f" "$to"
        else
          [ -n "$DryRun" ] && echo "skip '$f'"
        fi
      done
}

# Do not execute if being sourced
[ "${0#*cpx}" != "$0" ] && cpx "$@"

Örnek kullanım

EXCLUDE="
.git
my_secret_stuff
"
cpr "$HOME/my_stuff" "/media/usb" "$EXCLUDE"

Birinin cevabının, sorunun ne olduğunu ve bunu nasıl düzeltebileceğinizi açıklamadan "başarısız olacağını" söylemek yararsız görünüyor ...
underscore_d

@underscore_d: doğru, gez, esp şimdi neyin başarısız olduğunu hatırlayamıyorum gibi :-(
go2null

Birden çok şey: (1) dosyaları birden çok kez kopyalar ve (2) mantık hala hariç tutulacak dosyaları kopyalar. İ = foo kullanarak döngüler boyunca çalıştırın: i = test.txt gibi başka bir dosya için 4 yerine 3 kez kopyalanır.
Eric Bringley

1
Steve'in cevabının eksikliklerini açıkladığı için @EricBringley'e teşekkürler. (Yine de denenmemiş olduğunu söyledi .)
go2null
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.