Kopieren einer einzelnen Datei in mehrere Verzeichnisse mit cp

12

Diese Frage ist eine Art Fortsetzung meiner früheren Frage, mit der ich zahlreiche Verzeichnisse erstellt habemkdir .

Ich benutze die bashShell. Ich habe fünfzig Verzeichnisse erstellt, die jeweils mit dem Präfix "s" beginnen.

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

welche auf die zweite Ziffer mit Nullen auffüllt. Das heißt, die Verzeichnisse , die ich erhalten sind von der Form s01, s02, ..., s49, s50.

Jetzt möchte ich verwenden, cpum eine einzelne Datei (zum Beispiel test.txt) in jedes der fünfzig Verzeichnisse zu kopieren . Ist es möglich, dies in analoger Weise wie oben zu tun? Zum Beispiel würde das folgende funktionieren? Ich bin relativ neu in Unix / Linux, daher möchte ich das erst wirklich ausprobieren, wenn mir jemand einen Hinweis gibt, dass es sicher ist.

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

Wenn Sie sich die manSeite cpansehen, sieht es nicht so aus, als würden cpmehrere Ziele wie dieses unterstützt:

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.
Andrew
quelle

Antworten:

7

Wenn Sie die Ausgabe Ihres Befehls verwenden möchten, um die Datei in jedes Verzeichnis zu kopieren cp, können Sie sie jederzeit weiterleiten an xargs:

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

Es sollte keine Bedenken hinsichtlich der Sicherheit beim Parsen der Ausgabe geben, da Sie das Format und den Inhalt bereits im Voraus kennen - das Risiko, dass Metazeichen und Leerzeichen in Dateinamen auftreten, spielt hier keine Rolle.

Angenommen, die Verzeichnisse existieren bereits, könnten Sie alternativ Folgendes versuchen:

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

oder ohne Pfeife:

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

Die letzten beiden Befehle finden alle Dateien im aktuellen Verzeichnis und cp test.txtzu diesen. Die -maxdepth 1Option wird vermieden , alle Unterverzeichnisse , die Datei als auch zu empfangen. Seien Sie gewarnt , dass 's[0-9][0-9]'gegen wird passend svon zwei beliebigen Ziffern folgen, was bedeutet , wenn aus irgendeinem Grund Sie haben s99in der cwd, es wird auch eine Kopie erhalten test.txt.

tojrobinson
quelle
8

Sie können die Shell auch die Iterationen mit einer forSchleife ausführen lassen. Dies ist die grundlegendste Methode, die sich nicht auf externe Tools wie paralleloder stützt xargs, und ich finde es am einfachsten zu verstehen:

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

Es gibt eine Million andere Möglichkeiten, dies zu schreiben, zB:

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

Wenn Sie überprüfen möchten, was ausgeführt werden würde, können Sie den Befehlen etwas voranstellen echo, wodurch die Zeile gedruckt und nicht ausgeführt wird:

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

Ausgänge:

mkdir s01
cp test.txt s01
mkdir s02
cp test.txt s02
mkdir s03
cp test.txt s03
# etc.
Jim Paris
quelle
2

Sie können GNU auch parallel verwenden . Unter der Annahme , Sie in das Verzeichnis mit text.txt und Ihre 50 dirs befinden sich in /my/50dirs/path(wie /my/50dirs/path/s01, /my/50dirs/path/s02etc) Sie laufen würde:

seq -w 01 50 | parallel -j1 cp text.txt /my/50dirs/path/s{}
don_crissti
quelle
2
Besser machen Sie das parallel -j1, sonst gibt es einen Job pro Kern und auf einem Multicore-Rechner konkurrieren die Jobs um IO.
Gilles 'SO - hör auf, böse zu sein'