Jak skopiować plik do wielu katalogów za pomocą polecenia gnu cp

210

Czy można skopiować pojedynczy plik do wielu katalogów za pomocą polecenia cp?

Próbowałem następujących, które nie działały:

cp file1 /foo/ /bar/
cp file1 {/foo/,/bar}

Wiem, że jest to możliwe przy użyciu pętli for lub find. Ale czy jest to możliwe przy użyciu polecenia gnu cp?

Tom Feiner
źródło

Odpowiedzi:

106

Nie, cpmożna skopiować wiele źródeł, ale skopiuje tylko do jednego miejsca docelowego. Musisz zorganizować cpwielokrotne wywoływanie - raz na miejsce docelowe - dla tego, co chcesz zrobić; używając, jak mówisz, pętli lub innego narzędzia.

księżycowy cień
źródło
Dziękuję za odpowiedź! Teraz, gdy myślę o tym trochę więcej, bez dodatkowych flag (które nie istnieją) cp nie będzie wiedział, co jest źródłem, a co DEST reż.
Tom Feiner
10
To nie jest poprawna odpowiedź. Zobacz odpowiedź Roberta Gamble.
PlagueHammer
23
@Nocturne: która część tego, co powiedziałem, jest nieprawidłowa? Robert podaje przykład użycia innego narzędzia do wielokrotnego wywoływania CP, jak sugeruję. Istnieje wiele możliwych rozwiązań, które polegają na użyciu innych narzędzi lub konstrukcji do tego celu, ale PO wskazał, że już wiedział, że jest to możliwe.
księżyc księżyca
2
Niestety byłoby wspaniale, gdyby cp (i scp) wspierały tę funkcję. Jednak możemy użyć tee do podziału. superuser.com/questions/32630/…
Simon
4
@moonshadow: Oczywiście twoja odpowiedź jest poprawna. Myślę, że PlagueHammer chce powiedzieć, że w tym kontekście druga odpowiedź jest bardziej przydatna. Być może w odpowiedzi umieścisz coś takiego?
Spokojnie,
585

Nie możesz tego zrobić cpsam, ale możesz połączyć cpz xargs:

echo dir1 dir2 dir3 | xargs -n 1 cp file1

Skopiuje file1się dir1, dir2oraz dir3. xargszadzwoni cp3 razy, aby to zrobić, zobacz stronę podręcznika, aby xargsuzyskać szczegółowe informacje.

Robert Gamble
źródło
3
Więcej informacji na temat xargs: cyberciti.biz/faq/…
Chris Bier
24
@ Simon jak to zrobić? „Nie możesz tego zrobić cpsam”. Tylko dlatego, że odpowiedź była pomocna, sugerując inny sposób, nie oznacza, że ​​na pytanie nie udzielono odpowiedzi.
Nicole,
3
@NickC Pytający sprecyzował: „Wiem, że jest to możliwe przy użyciu pętli for lub find. Ale czy jest to możliwe przy użyciu polecenia gnu cp?” Dobra odpowiedź to jedna zaakceptowana.
Simon
25
Zastrzeganie, że odpowiedzi będą akceptowane na podstawie tego, czy technicznie odpowiedzą na pytanie, byłoby zbyt pedantyczne i niezbyt przydatne.
Tryktrak
4
Bardzo pomocne! Dla innych początkujących, takich jak ja: nie możesz używać wyrażenia regularnego z cp, ale możesz w pierwszej części tego polecenia (np echo dir[1-3] | xargs -n 1 cp filename.).
Jason
77

Symbole wieloznaczne działają również z kodem Robertsa

echo ./fs*/* | xargs -n 1 cp test 
Paweł
źródło
i cały komentarz ... Na przykład, aby przenieść plik będący własnością root (właściwie dowiązanie symboliczne), który był na moim pulpicie na pulpit wszystkich użytkowników, najpierw musiałem sudo su (nie działał inaczej), a następnie użyłem: echo / home / * / Desktop / | xargs -n 1 cp -av / home / myusername / Desktop / file.
David G,
19

O ile widzę, możesz użyć następujących czynności:

ls | xargs -n 1 cp -i file.dat

-iOpcja cppomocą poleceń, które będą się pytanie, czy zapisać plik w bieżącym katalogu z file.dat. Chociaż nie jest to w pełni zautomatyzowane rozwiązanie, udało mi się.

Evgeny
źródło
1
Chociaż dobrze jest dodać -istrażnika, czy nie zachęci cię to do zapisania każdego pliku? zamiast kopiowania do katalogów?
Jeż
1
@ Jeż Cóż, myślę, że to polecenie jest przydatne, gdy w katalogu znajduje się plik i chce się go skopiować do podkatalogów katalogu. W takim przypadku plik można zastąpić tylko raz. Dziękuję za twoje pytanie!
Evgeny
2
Dla mnie wydrukował serię cp: overwritepytań, ale nie musiałem odpowiadać na żadne z nich i nie zastąpił plików.
Evgeni Sergeev
Wydrukowano również serię pytań + skopiowano do pliku o nazwie dir ze znakiem „:” na końcu, brak działającego rozwiązania, rozwiązanie Paula działa idealnie
jgpATs2w
19

Chciałbym użyć cati teena podstawie odpowiedzi, które widziałem na /superuser/32630/parallel-file-copy-from-single-source-to-multiple-targets zamiastcp .

Na przykład:

cat inputfile | tee outfile1 outfile2 > /dev/null
deterb
źródło
1
Pobieżny test, który właśnie uruchomiłem, pokazuje, że jest to najlepszy wynik, jeśli miejscem docelowym są różne dyski fizyczne (przechowujące dwie fizyczne kopie bazy plików, takie jak źródłowe wideo do filmu cyfrowego).
curiouser
1
Jeśli korzystasz z wersji bash 3.0 lub nowszej, możesz używać zakresów w następujący sposób:cat <inputfile> | tee /path-to-files/outfile{1..4} > /dev/null
Samuel
tee < inputfile outfile1 outfile2 > /dev/nulljest również użytecznym wzorem, jak pokazuje odpowiedź Taywee. Zwróć uwagę na użycie przekierowania io z „<”, aby rurociągi od kota nie były potrzebne.
Alex Telon
10

Wszystkie te odpowiedzi wydają się bardziej skomplikowane niż oczywiste:

for i in /foo /bar; do cp "$file1" "$i"; done
Woskrat
źródło
elegancki i działający, aby zrobić to dla wszystkich katalogów w bieżącym katalogu, można użyćfor d in */ ; do cp $file "$i" done
FantomX1
9

ls -db di*/subdir | xargs -n 1 cp File

-bw przypadku, gdy w nazwie katalogu jest spacja, w przeciwnym razie zostanie ona podzielona przez xargs jako inny element, miał ten problem z wersją echa

thAAAnos
źródło
6

Nie używam cp per se, ale ...

To przyszło mi do głowy w kontekście kopiowania wielu nagrań Gopro z (wolnej) karty SD na trzy (wolne) dyski USB. Chciałem odczytać dane tylko raz, ponieważ zajęło to wieczność. I chciałem, żeby to było rekurencyjne.

$ tar cf - src | tee >( cd dest1 ; tar xf - ) >( cd dest2 ; tar xf - ) | ( cd dest3 ; tar xf - )

(I możesz dodać więcej z tych sekcji> (), jeśli chcesz uzyskać więcej wyników).

Nie testowałem tego, ale jest zdecydowanie dużo szybszy niż cp-in-a-loop (lub kilka równoległych wywołań cp).

oggust
źródło
5

Aby użyć kopiowania xargsdo katalogów za pomocą symboli wieloznacznych w systemie Mac OS, jedynym rozwiązaniem, które działało dla mnie ze spacjami w nazwie katalogu, jest:

find ./fs*/* -type d -print0 | xargs -0 -n 1 cp test 

Gdzie testjest plik do skopiowania
I ./fs*/*katalogi do skopiowania

Problem polega na tym, że xargs widzi spacje jako nowy argument, rozwiązania zmiany znaku separatora za pomocą -dlub -Eniestety nie działają poprawnie w systemie Mac OS.

MegaCookie
źródło
4

Jeśli chcesz to zrobić bez polecenia rozwidlonego:

tee <inputfile file2 file3 file4 ... >/dev/null

Taywee
źródło
2

Zasadniczo równoważne z odpowiedzią xargs, ale w przypadku, gdy chcesz wykonać równoległe:

parallel -q cp file1 ::: /foo/ /bar/

Na przykład, aby skopiować plik1 do wszystkich podkatalogów bieżącego folderu (w tym rekurencji):

parallel -q cp file1 ::: `find -mindepth 1 -type d`

Uwaga: Prawdopodobnie zapewnia to jedynie zauważalne zwiększenie prędkości w bardzo szczególnych przypadkach użycia, np. Jeśli każdy katalog docelowy jest odrębnym dyskiem.

Jest również funkcjonalnie podobny do argumentu „-P” dla xargs.

alainv
źródło
0

Nie, nie możesz.

Wielokrotnie odkryłem, że mogę skorzystać z tej funkcji, dlatego stworzyłem własne narzędzie, aby to dla mnie zrobić.

http://github.com/ddavison/branch

dość proste -
branch myfile dir1 dir2 dir3

ddavison
źródło
Często zdarzają się sytuacje, w których napisałbym własny skrypt, ale obecnie używam tak wielu maszyn, że utrzymywanie ich wszystkich w synchronizacji wydaje się dużym problemem. Gdyby tylko istniał sposób na zamontowanie katalogu internetowego w chmurze, /ena przykład tylko raz na każdej maszynie, mógłbym pisać własne narzędzia i przechowywać je na zawsze.
Evgeni Sergeev
0
ls -d */ | xargs -iA cp file.txt A
Sj Lee
źródło
1
A może trochę wyjaśnienia?
min.
To faktycznie działa, ale wyjaśnienie byłoby świetne
Declex
0

Załóżmy, że chcesz skopiować fileName.txtdo wszystkich podkatalogów w bieżącym katalogu roboczym.

  1. Uzyskaj wszystkie nazwy podkatalogów lsi zapisz je w pliku tymczasowym, powiedz:allFolders.txt

    ls > allFolders.txt
  2. Wydrukuj listę i przekaż ją do polecenia xargs.

    cat allFolders.txt | xargs -n 1 cp fileName.txt
Devendra Lattu
źródło
0

Innym sposobem jest użycie kota i tee w następujący sposób:

cat <source file> | tee <destination file 1> | tee <destination file 2> [...] > <last destination file>

Myślę, że byłoby to dość nieefektywne, ponieważ zadanie zostanie podzielone na kilka procesów (jeden na miejsce docelowe), a dysk twardy zapisuje kilka plików jednocześnie na różnych częściach talerza. Jednak jeśli chcesz zapisać plik na kilku różnych dyskach, ta metoda prawdopodobnie byłaby dość wydajna (ponieważ wszystkie kopie mogłyby się odbywać jednocześnie).

jww
źródło
0

Za pomocą skryptu bash

DESTINATIONPATH[0]="xxx/yyy"
DESTINATIONPATH[1]="aaa/bbb"
                ..
DESTINATIONPATH[5]="MainLine/USER"
NumberOfDestinations=6

for (( i=0; i<NumberOfDestinations; i++))
    do
        cp  SourcePath/fileName.ext ${DESTINATIONPATH[$i]}

    done
exit
Patrick Manley
źródło
Głosowałem za tym. Pytanie konkretnie dotyczy rozwiązania niepętlowego.
Alex Telon
-1

jeśli chcesz skopiować wiele folderów do wielu folderów, możesz zrobić coś takiego:

echo dir1 dir2 dir3 | xargs -n 1 cp -r / ścieżka / toyourdir / {subdir1, subdir2, subdir3}

Izaak
źródło
-1

Jeśli wszystkie katalogi docelowe pasują do wyrażenia ścieżki - tak jak wszystkie podkatalogi path/to- użyj tego findw kombinacji z cpnastępującymi:

find ./path/to/* -type d -exec cp [file name] {} \;

Otóż ​​to.

Mig82
źródło
Głosowałem za tym. Pytanie konkretnie dotyczyło rozwiązania nie do znalezienia.
Alex Telon
Dziękujemy za bycie tak dokładnym @AlexTelon. Chyba za tym tęskniłem. Mam nadzieję, że również byłeś konsekwentny i oddałeś głos negatywny na każdą inną odpowiedź używaną findw wątku.
Mig82
-2

Jeśli musisz sprecyzować, do których folderów skopiować plik, możesz połączyć find z jednym lub kilkoma greps. Na przykład, aby zastąpić dowolne wystąpienia pliku favicon.ico w dowolnym podfolderze, którego możesz użyć:

find . | grep favicon\.ico | xargs -n 1 cp -f /root/favicon.ico
Kristofer
źródło
-3

Spowoduje to skopiowanie do bezpośrednich podkatalogów, jeśli chcesz wejść głębiej, dostosuj -maxdepthparametr.

find . -mindepth 1 -maxdepth 1 -type d| xargs -n 1 cp -i index.html

Jeśli nie chcesz kopiować do wszystkich katalogów, mam nadzieję, że możesz filtrować katalogi, które Cię nie interesują. Przykład kopiowania do wszystkich folderów zaczynających się od a

find . -mindepth 1 -maxdepth 1 -type d| grep \/a |xargs -n 1 cp -i index.html

Jeśli kopiujesz do dowolnego katalogu katalogów, będziesz potrzebować sugestii Roberta Gamble'a.

Jeż
źródło
-3

Lubię kopiować plik do wielu katalogów jako takich: cp file1 /foo/; cp file1 /bar/; cp file1 /foo2/; cp file1 /bar2/ I kopiować katalog do innych katalogów: cp -r dir1/ /foo/; cp -r dir1/ /bar/; cp -r dir1/ /foo2/; cp -r dir1/ /bar2/

Wiem, że to tak, jakby wydawać kilka poleceń, ale działa dobrze, gdy chcę wpisać linię 1 i odejść na chwilę.

Stace Fauske
źródło
7
Na 6-letnie pytanie udzielono 15 innych odpowiedzi. Twoja odpowiedź musi być dość nowatorska. Moja opinia - nie jest.
Craig S. Anderson
-4

Na przykład jeśli jesteś w katalogu nadrzędnym folderów docelowych, możesz:

dla i w $ (ls); zrób plik źródłowy cp $ i; Gotowe

Behrooz
źródło
Pytanie mówi, że jest to możliwe dzięki pętli for, więc to tak naprawdę nic nie dodaje.
LJNielsenDk
Doceniony. Nigdy nie próbuj analizować danych wyjściowychls i zawsze cytuj zmienne. for i in ./*; do cp sourcefile "$i"; done
sleblanc