Kopiowanie jednego pliku do wielu katalogów za pomocą cp

12

To pytanie jest kontynuacją mojego wcześniejszego pytania, polegającego na tworzeniu wielu katalogówmkdir .

Używam bashpowłoki. Utworzyłem pięćdziesiąt katalogów, każdy rozpoczynający się od przedrostka „s”, za pomocą polecenia:

mkdir $(printf "s%02i " $(seq 1 50))

który dopełnia do drugiej cyfry zerami. Oznacza to, że katalogi, które mogę otrzymać są postaci s01, s02, ..., s49, s50.

Teraz chciałbym użyć cpdo skopiowania jednego pliku (na przykład test.txt) do każdego z pięćdziesięciu katalogów. Czy można to zrobić w sposób analogiczny do powyższego? Na przykład, czy następujące działania będą działać? Jestem stosunkowo nowy w systemach Unix / Linux, więc tak naprawdę nie chcę tego próbować, dopóki ktoś nie poda mi wskazówki, że jest bezpieczny.

cp test.txt $ (printf "s% 02i.txt" $ (seq 1 50))

Patrząc na manstronę cp, nie wygląda na to, że cpobsługuje wiele takich miejsc docelowych, jednak:

NAME
       cp - copy files and directories

SYNOPSIS
       cp [OPTION]... [-T] SOURCE DEST
       cp [OPTION]... SOURCE... DIRECTORY
       cp [OPTION]... -t DIRECTORY SOURCE...

DESCRIPTION
       Copy SOURCE to DEST, or multiple SOURCE(s) to DIRECTORY.

       Mandatory  arguments  to  long  options are mandatory for short options
       too.
Andrzej
źródło

Odpowiedzi:

7

Jeśli chcesz użyć danych wyjściowych polecenia do skopiowania pliku do każdego katalogu za pomocą cp, zawsze możesz przesłać go do xargs:

printf "s%02i " $(seq 1 50) | xargs -n 1 cp test.txt

Nie powinno być żadnych obaw związanych z bezpieczeństwem parsowania danych wyjściowych, ponieważ znasz ich format i treść - ryzyko napotkania meta znaków i spacji w nazwach plików nie jest tak naprawdę problemem.

Alternatywnie, zakładając, że katalogi już istnieją, możesz spróbować czegoś takiego:

find . -maxdepth 1 -type d -name 's[0-9][0-9]' -print0 | xargs -0 -I {} cp test.txt {}

lub bez rury:

find . -maxdepth 1 -type d -name 's[0-9][0-9]' -exec cp test.txt {} \;

Ostatnie dwa polecenia znajdą dowolne pliki w bieżącym katalogu i cp test.txtdo nich. Ta -maxdepth 1opcja pozwoli również uniknąć odbierania pliku przez podkatalogi. Ostrzegamy, że 's[0-9][0-9]'pasujące do, sa następnie dowolne dwie cyfry, co oznacza, że ​​z jakiegoś powodu masz s99w cwd, otrzymasz również kopię test.txt.

tojrobinson
źródło
8

Możesz także pozwolić powłoce wykonywać iteracje za pomocą forpętli. Jest to najbardziej podstawowy sposób, który nie opiera się na zewnętrznych narzędziach takich jak parallellub xargs, i uważam, że najłatwiej jest to zrozumieć:

for name in $(printf "s%02i " $(seq 1 50)); do
    mkdir $name
    cp test.txt $name
done

Istnieje milion innych sposobów na napisanie tego, np .:

for name in $(seq -w 1 50); do
    mkdir s$name
    cp test.txt s$name
done

Jeśli chcesz sprawdzić, co zostanie wykonane przed zrobieniem tego, możesz zrobić coś takiego, jak wstawianie poleceń za pomocą echo, które wypiszą wiersz zamiast go wykonać:

for name in $(seq -w 1 50); do
    echo mkdir s$name
    echo cp test.txt s$name
done

wyjścia:

mkdir s01
cp test.txt s01
mkdir s02
cp test.txt s02
mkdir s03
cp test.txt s03
# etc.
Jim Paris
źródło
2

Możesz także użyć GNU równolegle . Zakładając, że znajdują się w katalogu zawierającym text.txt i twoi 50 katalogi znajdują się w /my/50dirs/path(jak /my/50dirs/path/s01, /my/50dirs/path/s02etc) by uruchomić:

seq -w 01 50 | parallel -j1 cp text.txt /my/50dirs/path/s{}
don_crissti
źródło
2
Lepiej to zrobić parallel -j1, w przeciwnym razie będzie jedno zadanie na rdzeń, a na maszynie wielordzeniowej zadania będą konkurować o IO.
Gilles „SO- przestań być zły”