Kopieren mehrerer Dateien in mehrere Verzeichnisse

Kopieren mehrerer Dateien in mehrere Verzeichnisse

Ich habe ein Problem beim Kopieren vieler Dateien in verschiedene Verzeichnisse. Lassen Sie es mich besser erklären:

Nehmen wir an, ich habe Folgendes in einem Verzeichnis:

$ ls
file1 file2 file3 file4 file5 dir1 dir2 dir3

und ich möchte jede Datei* in jedem Verzeichnis* mit einem einzigen Befehl kopieren. Ich habe es mit Folgendem versucht:

 echo dir{1..3} | xargs cp file{1..5} '{}' \;

Meine Absicht war, xargs anzuweisen, jedes einzelne Verzeichnis* von Echo zu verarbeiten und alle Dateien in der verarbeiteten Eingabe zu kopieren, aber dies und ähnliches funktionierten nicht. Ich möchte die Verwendung eines Skripts vermeiden, da dies eine Aufgabe ist, die ich für etwa 20 Verzeichnisse wiederholen muss und die Namen der Dateien leicht unterschiedlich sind. Daher würde ich lieber einen Befehl als ein Skript ändern.

Antwort1

echo dir[1-3] | xargs -r -n1 cp file[1-5]

Antwort2

Sie machen einen kleinen Fehler bei der Verwendung von xargs. Ohne den Parameter -n hängt xargs alle Parameter in der Eingabe an den Befehl an und echo dir{1..3}fügt zwischen den einzelnen Einträgen nicht den erforderlichen Wagenrücklauf ein. Daher betrachtet xargs das Ergebnis als einen Parameter.

xargs hat eine Option -n, mit der die Anzahl der Einträge begrenzt werden kann, und Sie müssen die Verzeichnisse mit einem \n oder \0 als Trennzeichen auflisten:

find . -mindepth 1 -maxdepth 1 -type d -print0 | xargs -0 -n 1 cp file{1..5}

Der Befehl „Find“ sucht nach allen Verzeichnissen im aktuellen und verwendet \0 als Trennzeichen (was besser funktioniert, wenn Sie Verzeichnisse mit Leerzeichen haben) und xargs verwendet \0 als Trennzeichen und startet den Befehl jedes Mal mit nur 1 Parameter.

Antwort3

Wenn sie tatsächlich solche Namen haben, sollte etwa das Folgende funktionieren:

#!/bin/bash
shopt -s nullglob
for dir in dir*/; do
    cp file* "$dir"
done

Wenn Sie alle Dateien unabhängig vom Namen in alle Verzeichnisse kopieren möchten:

#!/bin/bash
shopt -s nullglob dotglob
for dir in */; do
    for file in *; do
        [[ -f $file ]] && cp "$file" "$dir"
    done
done

Antwort4

Sie sind fast am Ziel. Sie müssen cpfür jedes Zielverzeichnis einen separaten Befehl ausführen, da cpnur eine Kopie jeder Quelldatei erstellt wird. Der Hauptzweck von xargsbesteht darin, einen Befehl mit mehreren Argumenten auszuführen, aber Sie können ihm mit der Option sagen, dass er jeweils nur ein einzelnes Element übergeben soll -n. Außerdem {} ;ist die Syntax von find … -exec; Sie benötigen (und können) sie nicht mit xargs.

echo dir{1..3} | xargs -n 1 cp file{1..5}

Beachten Sie, dass dies nur funktioniert, wenn Ihre Verzeichnisnamen keine Leerzeichen oder die Zeichen enthalten \'", da xargses keine Möglichkeit gibt, festzustellen, ob diese Zeichen Teil von Dateinamen sind und keine Anführungszeichen und Trennzeichen für Eingabedateien sind. Eine alternative Methode, bei der dieses Problem nicht auftritt, ist die Verwendung einer Shell-Schleife:

for d in dirs{1..3}; do
  cp file{1..5} "$d"
done

Dies alles setzt voraus, dass Sie Dateien und Verzeichnisse problemlos anhand ihrer Namen unterscheiden können. Wenn das nicht möglich ist, können Sie Verzeichnisse abgleichen, indem Sie /am Ende ein hinzufügen. Beispielsweise */stimmt mit allen Verzeichnissen in den aktuellen Verzeichnissen überein, foo[0-9]*/stimmt mit allen Verzeichnissen überein, deren Name mit foound einer Ziffer beginnt, usw. In den meisten Shells gibt es keine ähnliche Möglichkeit, nur Nicht-Verzeichnisse abzugleichen. Wenn Sie jedoch Verzeichnisse cpohne Argument übergeben, um eine rekursive Kopie zu erstellen, werden die Verzeichnisse mit einer Fehlermeldung ignoriert.

for d in */; do
  cp * "$d"
done

In zsh können Sie verwendenGlob-Qualifikationum nur bestimmte Dateitypen abzugleichen.

for d in *(/); do
  cp *(.) $d
done

verwandte Informationen