Akzeptierte Antwort ist falsch (es gibt eine solche Option für cp). Siehe zweite Antwort von Paul Whipp.
Ronenz
1
@ Ronenz, ich stimme zu, dass es eine erwähnenswerte Option in GNU gibt cp(wie von Paul Whipp beantwortet), aber sie ist nicht so allgemein wie vom OP angefordert. Es kann kopieren a/foo/bar/filezu , b/foo/bar/fileaber es kann nicht kopieren filezu b/foo/bar/file. (dh es funktioniert nur, um übergeordnete Verzeichnisse zu erstellen, die bereits im Fall der ersten Datei vorhanden waren, aber es können keine beliebigen Verzeichnisse erstellt werden)
Sudo Bash
Das sieht nach einer netten Feature-Anfrage für cp aus. Gibt es eine Chance, dass wir in naher Zukunft einen solchen Befehlszeilenschalter bekommen?
Ich glaube nicht, dass Sie das brauchen test -d: ist mkdir -pimmer noch erfolgreich, auch wenn das Verzeichnis bereits existiert.
Ephemient
Ups, richtig. Aber dann kann Test eine eingebaute Bash sein (besonders wenn als [[-d "$ d"]] geschrieben) und mkdir kann nicht ;-)
Michael Krelin - Hacker
1
mkdirist ein eingebautes in BusyBox;)
Ephemient
7
@holms $dist eine Variable, die vermutlich das betreffende Verzeichnis enthält. Ich meine, wenn Sie es dreimal wiederholen müssen, werden Sie es wahrscheinlich zuerst der Variablen zuweisen.
Michael Krelin - Hacker
237
Wenn beide der folgenden Aussagen zutreffen:
Sie verwenden die GNU-Version von cp(und nicht beispielsweise die Mac-Version) und
Sie kopieren aus einer vorhandenen Verzeichnisstruktur und müssen diese nur neu erstellen
--parents
Form the name of each destination file by appending to the target
directory a slash and the specified name of the source file. The
last argument given to `cp' must be the name of an existing
directory. For example, the command:
cp --parents a/b/c existing_dir
copies the file `a/b/c' to `existing_dir/a/b/c', creating any
missing intermediate directories.
Beispiel:
/tmp $ mkdir foo
/tmp $ mkdir foo/foo
/tmp $ touch foo/foo/foo.txt
/tmp $ mkdir bar
/tmp $ cp --parents foo/foo/foo.txt bar
/tmp $ ls bar/foo/foo
foo.txt
Dies funktioniert nicht unter Mac OS X, daher denke ich, dass es Linux-spezifisch ist.
Olt
7
Ich würde gnu-spezifisch sagen. Wenn Sie haben macports, können Sie coreutils und seine installieren gcp.
Michael Krelin - Hacker
16
Mann, Linux hat alles
Ziggy
19
Ich denke, dies ist die Antwort auf eine etwas andere Frage, obwohl es die Antwort ist, nach der ich gesucht habe (und daher die, die ich positiv bewertet habe). Ich denke, dies ist die Lösung, vorausgesetzt, Sie möchten, dass die übergeordneten
Zielverzeichnisse
7
Dies setzt voraus, dass das Verzeichnis 'bar' bereits vorhanden ist. Die ursprüngliche Frage impliziert jedoch, wie automatisch 'bar' erstellt wird, wenn es als Ziel angegeben wird und noch nicht vorhanden ist. Die Antwort darauf liefert @ MichaelKrelin-Hacker.
Donnerstag,
69
Kurze Antwort
So kopieren myfile.txtzu /foo/bar/myfile.txtverwenden:
mkdir -p /foo/bar && cp myfile.txt $_
Wie funktioniert das?
Da dies einige Komponenten enthält, werde ich Schritt für Schritt die gesamte Syntax behandeln.
Das im POSIX-Standard angegebene Dienstprogramm mkdir erstellt Verzeichnisse. Das Argument, pro der Dokumentation, wird dazu führen , mkdir zu-p
Erstellen Sie fehlende Komponenten für den Zwischenpfadnamen
dass bedeutet , wenn Sie anrufen mkdir -p /foo/bar, mkdir schaffen wird /foound/foo/bar wenn /fookeine vorhanden ist. (Ohne -pwird stattdessen ein Fehler ausgegeben.
Der &&Listenoperator, wie im POSIX-Standard (oder im Bash-Handbuch, wenn Sie dies bevorzugen) dokumentiert , hat den Effekt, dass er cp myfile.txt $_nur ausgeführt wird, wenn er mkdir -p /foo/barerfolgreich ausgeführt wird. Dies bedeutet, dass der cpBefehl nicht versucht, ausgeführt zu werden, wenn er mkdiraus einem der vielen Gründe fehlschlägt .
Schließlich ist das, das $_wir als zweites Argument übergeben, cpein "spezieller Parameter", der nützlich sein kann, um zu vermeiden, dass lange Argumente (wie Dateipfade) wiederholt werden, ohne dass sie in einer Variablen gespeichert werden müssen. Gemäß dem Bash-Handbuch gilt Folgendes:
Erweitert sich zum letzten Argument des vorherigen Befehls
In diesem Fall haben /foo/barwir das weitergegeben mkdir. Der cpBefehl wird also erweitert und in das neu erstellte Verzeichnis cp myfile.txt /foo/barkopiert .myfile.txt/foo/bar
Beachten Sie, dass $_ist nicht Teil des POSIX - Standard , so dass theoretisch eine Unix - Variante könnte eine Schale hat , die nicht dieses Konstrukt nicht unterstützt. Ich kenne jedoch keine modernen Muscheln, die nicht unterstützt werden $_. sicherlich tun es Bash, Dash und zsh alle.
Ein letzter Hinweis: Der Befehl, den ich zu Beginn dieser Antwort gegeben habe, setzt voraus, dass Ihre Verzeichnisnamen keine Leerzeichen enthalten. Wenn Sie mit Namen mit Leerzeichen arbeiten, müssen Sie sie so zitieren, dass die verschiedenen Wörter werden nicht als unterschiedliche Argumente zu mkdiroder behandelt cp. Ihr Befehl würde also tatsächlich so aussehen:
mkdir -p "/my directory/name with/spaces"&& cp "my filename with spaces.txt""$_"
Nebenbei: Ich bin normalerweise enttäuscht über den Mangel an Details bei Fragen zu Bash- oder Unix-Shell-Befehlen in Stack Overflow, die häufig einen komplizierten und extrem dichten Einzeiler auslösen, der schwer zu entfernen ist, wenn Sie noch kein Unix-Assistent sind. Ich habe versucht, hier das entgegengesetzte Extrem zu wählen und beide erklären jedes Detail der Syntax und verlinken auf die entsprechenden Stellen, um Dokumentation darüber zu finden, wie dieses Zeug funktioniert. Ich hoffe das hilft zumindest einigen Leuten. Gutschrift, wo fällig: Ich habe diesen Ansatz aus dieser Antwort auf eine doppelte Frage geklaut
Mark Amery
Ich habe $ _ noch nie gesehen. Worauf bezieht es sich? der im letzten Befehl verwendete Ordner?
Thebunnyrules
9
@thebunnyrules Aber ... aber ... es gibt ein "Wie funktioniert das?" Abschnitt in meiner Antwort, der buchstäblich mehrere Absätze enthält, die speziell der Frage gewidmet sind, die Sie gerade gestellt haben. Es fühlt sich ignoriert und ungeliebt an. :(
Mark Amery
Das tut mir leid. Du hast absolut recht. Ich wusste bereits alles andere in Ihrer Antwort, also habe ich es schnell durchgesehen. Ich hätte es genauer lesen sollen.
Thebunnyrules
Wow, du hast wirklich viel Arbeit in diese Antwort gesteckt ... Danke dafür. Es war schön zu lernen über: $ _. Ich kann mir vorstellen, dass ich es von nun an ziemlich oft benutze. Ich habe ein Skript geschrieben, um den gesamten Prozess zu automatisieren und in diesen Thread zu stellen. Probieren
thebunnyrules
39
Eine so alte Frage, aber vielleicht kann ich eine alternative Lösung vorschlagen.
Mit dem installProgramm können Sie Ihre Datei kopieren und den Zielpfad "on the fly" erstellen.
Sie müssen auch den Namen der Zieldatei angeben , nicht nur den Zielpfad
Die Zieldatei ist ausführbar (zumindest soweit ich dies bei meinen Tests gesehen habe).
Sie können die Nummer 2 einfach ändern, indem Sie die -mOption zum Festlegen von Berechtigungen für die Zieldatei hinzufügen (Beispiel: -m 664Erstellt die Zieldatei mit Berechtigungen rw-rw-r--, genau wie das Erstellen einer neuen Datei mit touch).
Hat für meinen Gebrauch nicht wirklich funktioniert, aber cooler Trick! Ich werde daran denken.
Thebunnyrules
Beachten Sie, dass dieser Befehl die Zieldateien mit 755( rwxr-xr-x) Berechtigungen erstellt, was wahrscheinlich nicht erwünscht ist. Sie können etwas anderes mit dem angeben -mSchalter, aber ich konnte nicht einen Weg finden nur halten Sie die Dateiberechtigungen :(
törzsmókus
19
Shell-Funktion, die macht, was Sie wollen, und sie als "Begräbnis" -Kopie bezeichnet, weil sie ein Loch für die Datei gräbt, in der sie leben soll:
Sie sollten Anführungszeichen um den haben dirname $2zu
Tarnay Kálmán
4
@ Kalmi, für ein korrektes Zitat möchten Sie auch $2als Argument zitieren dirname. Wie mkdir -p "$(dirname "$2")". Ohne diese Angabe $2in cpnützt nichts;)
Michael Krelin - Hacker
3
Beachten Sie, dass diese Antwort davon ausgeht, dass $ 2 nicht bereits das Zielverzeichnis ist, andernfalls möchten Sie nur "mkdir -p" $ 2 "&& cp" $ 1 "" $ 2 "als Funktionskörper
user467257
Ich denke, das hat einen Fehler, wie @ user467257 hervorhebt. Ich denke nicht, dass dies behoben werden kann, da $ 2 in diesem Szenario zwischen dem Zielverzeichnis und der Zieldatei nicht eindeutig ist. Ich habe eine alternative Antwort gepostet, die dies anspricht.
Rich
@ Rich, ich bin nicht einverstanden, dass dies nicht reparierbar ist. Folgendes funktioniert sowohl für Dateien als auch für Verzeichnisse einwandfrei: mkdir -p dirname "$2"&& cp -r "$ 1" "$ 2"; Beachten Sie, dass die Backticks dirname $2nicht angezeigt werden, da SO sie als Codemarkierungen analysiert.
dirnamegibt Ihnen das übergeordnete Element des Zielverzeichnisses oder der Zieldatei. mkdir -p `dirname ...` erstellt dann dieses Verzeichnis und stellt sicher, dass beim Aufrufen von cp -r das richtige Basisverzeichnis vorhanden ist.
Der Vorteil dieser Übereltern besteht darin, dass sie für den Fall funktionieren, dass das letzte Element im Zielpfad ein Dateiname ist.
Eigentlich ist es überhaupt nicht dasselbe. Hierfür müssen Sie den Dateinamen zweimal übergeben (daher das Flag '-t') und die Ausführungsbits für die Datei setzen (daher das Beispiel '-m'). Dies sollte nicht die beste Antwort sein, da es die Frage nicht wirklich beantwortet - während meine es tut.
Spongman
1
Dies funktioniert für eine einzelne Datei. Berücksichtigen Sie einfach, dass dies theredie endgültige Datei und nicht das endgültige Unterverzeichnis ist.
kvantour
6
Bei allem Respekt für die obigen Antworten bevorzuge ich die Verwendung von rsync wie folgt:
$ rsync -a directory_name /path_where_to_inject_your_directory/
Ich habe es versucht und folgendes Ergebnis erzielt: rsync -a bull / some / hoop / ti / doop / ploop ERGEBNIS rsync: mkdir "/ some / hoop / ti / doop / ploop" fehlgeschlagen: Keine solche Datei oder Verzeichnis (2) rsync-Fehler : Fehler in Datei IO (Code 11) bei main.c (675) [Receiver = 3.1.2]
Wenn ich Ihren Vorschlag richtig verstehe, schlagen Sie vor, dass ich in meinem Befehl einen vollständigen Pfad zur Quelle, auch bekannt als use: "$ (pwd) / bull", anstelle des Dateinamens: bull? Die Sache ist, der Fehler ist, dass rsync das Zielverzeichnis erstellt, nicht die Quelle (bull). Mir scheint, rsync verwendet ein einfaches mkdir und kein mkdir -p.
Thebunnyrules
1
Übrigens ein großartiges Dienstprogramm, das ich möglicherweise in meinen Skripten verwende. Vielen Dank für die Empfehlung.
Thebunnyrules
1
rsync ist vorhersehbarer als cp. Wenn ich zum Beispiel möchte, cp /from/somedir /to-dirverhält sich cp anders, wenn /to-dires bereits existiert: Wenn es /to-direxistiert, cpwird erstellt /to-dir/some-dir, andernfalls wird nur der Inhalt von /from/somedirplatziert /to-dir. Verhält rsyncsich jedoch gleich für den Fall, /to-dir/some-dirdass immer erstellt wird.
JoeAC
5
Nur um fortzufahren und eine vollständige Arbeitslösung in einer Zeile zu geben. Seien Sie vorsichtig, wenn Sie Ihre Datei umbenennen möchten. Geben Sie eine Möglichkeit an, einen sauberen Verzeichnispfad zu mkdir bereitzustellen. $ fdst kann eine Datei oder ein Verzeichnis sein. Der nächste Code sollte auf jeden Fall funktionieren.
Vielen Dank! Das brauchte ich. In meinem Fall weiß ich nicht, ob das Ziel ein Verzeichnis hat oder nicht und ob das Verzeichnis existiert oder nicht. Dieser Code gibt mir das übergeordnete Verzeichnis, das ich dann sicher erstellen kann, wenn es nicht existiert
xbmono
4
Fügen Sie einfach Folgendes in Ihre .bashrc ein und optimieren Sie es bei Bedarf. Funktioniert in Ubuntu.
mkcp(){
test -d "$2"|| mkdir -p "$2"
cp -r "$1""$2"}
Beispiel: Wenn Sie die 'Test'-Datei in das Zielverzeichnis' d 'Use kopieren möchten,
mkcp test a/b/c/d
mkcp prüft zunächst, ob das Zielverzeichnis vorhanden ist oder nicht. Wenn nicht, erstellen Sie es und kopieren Sie die Quelldatei / das Quellverzeichnis.
Da andere die andere Antwort kommentierten, müssen Sie vor dem Aufruf nicht testen, ob das Verzeichnis vorhanden ist mkdir -p. Es wird erfolgreich sein, auch wenn es bereits existiert.
Zustimmen. In man cp:-R If source_file designates a directory, cp copies the directory and the entire subtree connected at that point.
BorracciaBlu
3
Ich habe ein Support-Skript für cp namens CP (Note Großbuchstaben) geschrieben, das genau dies tun soll. Das Skript prüft den von Ihnen eingegebenen Pfad auf Fehler (mit Ausnahme des letzten, der das Ziel ist). Wenn alles in Ordnung ist, führt es einen mkdir -p-Schritt aus, um den Zielpfad zu erstellen, bevor die Kopie gestartet wird. Zu diesem Zeitpunkt übernimmt das reguläre Dienstprogramm cp und alle Schalter, die Sie mit CP verwenden (wie -r, -p, -rpL werden direkt an cp weitergeleitet). Bevor Sie mein Skript verwenden, müssen Sie einige Dinge verstehen.
Auf alle Informationen hier kann mit CP --help zugegriffen werden. CP --help-all enthält die Schalter von cp.
reguläres cp kopiert nicht, wenn es den Zielpfad nicht findet. Sie haben kein solches Sicherheitsnetz für Tippfehler mit CP. Ihr Ziel wird erstellt. Wenn Sie also Ihr Ziel als / usrr / share / icons oder / usr / share / icon falsch schreiben, wird dies erstellt.
reguläres cp neigt dazu, sein Verhalten auf dem vorhandenen Pfad zu modellieren: cp / a / b / c / d hängt davon ab, ob d existiert oder nicht. Wenn d ein vorhandener Ordner ist, kopiert cp b in diesen Ordner und macht / c / d / b. Wenn d nicht existiert, wird b in c kopiert und in d umbenannt. Wenn d existiert, aber eine Datei ist und b eine Datei ist, wird es durch die Kopie von b überschrieben. Wenn c nicht existiert, kopiert cp nicht und wird beendet.
CP hat nicht den Luxus, sich an bestehenden Pfaden zu orientieren, daher muss es einige sehr feste Verhaltensmuster haben. CP geht davon aus, dass das zu kopierende Element im Zielpfad abgelegt wird und nicht das Ziel selbst ist (auch bekannt als umbenannte Kopie der Quelldatei / des Quellordners). Bedeutung:
"CP / a / b / c / d" führt zu / c / d / b, wenn d ein Ordner ist
"CP / a / b / c / b" führt zu / c / b / b, wenn b in / c / b ein Ordner ist.
Wenn sowohl b als auch d Dateien sind: CP / a / b / c / d führt zu / c / d (wobei d eine Kopie von b ist). Gleiches gilt für CP / a / b / c / b unter den gleichen Umständen.
Dieses Standard-CP-Verhalten kann mit dem Schalter "--rename" geändert werden. In diesem Fall wird davon ausgegangen, dass
"CP - Name / a / b / c / d" kopiert b in / c und benennt die Kopie in d um.
Einige abschließende Hinweise: Wie bei cp kann CP mehrere Elemente gleichzeitig kopieren, wobei der zuletzt aufgeführte Pfad als Ziel angenommen wird. Es kann auch Pfade mit Leerzeichen verarbeiten, solange Sie Anführungszeichen verwenden.
CP überprüft die von Ihnen eingegebenen Pfade und stellt sicher, dass sie vorhanden sind, bevor Sie die Kopie erstellen. Im strengen Modus (verfügbar über den Schalter --strict) müssen alle zu kopierenden Dateien / Ordner vorhanden sein, da sonst keine Kopie erfolgt. Im entspannten Modus (--relaxed) wird der Kopiervorgang fortgesetzt, wenn mindestens eines der von Ihnen aufgelisteten Elemente vorhanden ist. Der entspannte Modus ist die Standardeinstellung. Sie können den Modus vorübergehend über die Schalter oder dauerhaft ändern, indem Sie die Variable easy_going am Anfang des Skripts festlegen.
So installieren Sie es:
Führen Sie in einem Nicht-Root-Terminal Folgendes aus:
Fügen Sie in gedit das CP-Dienstprogramm ein und speichern Sie:
#!/bin/bash#Regular cp works with the assumption that the destination path exists and if it doesn't, it will verify that it's parent directory does.#eg: cp /a/b /c/d will give /c/d/b if folder path /c/d already exists but will give /c/d (where d is renamed copy of b) if /c/d doesn't exists but /c does.#CP works differently, provided that d in /c/d isn't an existing file, it assumes that you're copying item into a folder path called /c/d and will create it if it doesn't exist. so CP /a/b /c/d will always give /c/d/b unless d is an existing file. If you put the --rename switch, it will assume that you're copying into /c and renaming the singl item you're copying from b to d at the destination. Again, if /c doesn't exist, it will be created. So CP --rename /a/b /c/d will give a /c/d and if there already a folder called /c/d, contents of b will be merged into d. #cp+ $source $destination#mkdir -p /foo/bar && cp myfile "$_"
err=0# error count
i=0#item counter, doesn't include destination (starts at 1, ex. item1, item2 etc)
m=0#cp switch counter (starts at 1, switch 1, switch2, etc)
n=1# argument counter (aka the arguments inputed into script, those include both switches and items, aka: $1 $2 $3 $4 $5)
count_s=0
count_i=0
easy_going=true #determines how you deal with bad pathes in your copy, true will allow copy to continue provided one of the items being copied exists, false will exit script for one bad path. this setting can also be changed via the custom switches: --strict and --not-strict
verbal="-v"
help="===============================================================================\
\n CREATIVE COPY SCRIPT (CP) -- written by thebunnyrules\
\n===============================================================================\n
\n This script (CP, note capital letters) is intended to supplement \
\n your system's regular cp command (note uncapped letters). \n
\n Script's function is to check if the destination path exists \
\n before starting the copy. If it doesn't it will be created.\n
\n To make this happen, CP assumes that the item you're copying is \
\n being dropped in the destination path and is not the destination\
\n itself (aka, a renamed copy of the source file/folder). Meaning:\n
\n * \"CP /a/b /c/d\" will result in /c/d/b \
\n * even if you write \"CP /a/b /c/b\", CP will create the path /a/b, \
\n resulting in /c/b/b. \n
\n Of course, if /c/b or /c/d are existing files and /a/b is also a\
\n file, the existing destination file will simply be overwritten. \
\n This behavior can be changed with the \"--rename\" switch. In this\
\n case, it's assumed that \"CP --rename /a/b /c/d\" is copying b into /c \
\n and renaming the copy to d.\n
\n===============================================================================\
\n CP specific help: Switches and their Usages \
\n===============================================================================\n
\
\n --rename\tSee above. Ignored if copying more than one item. \n
\n --quiet\tCP is verbose by default. This quiets it.\n
\n --strict\tIf one+ of your files was not found, CP exits if\
\n\t\tyou use --rename switch with multiple items, CP \
\n\t\texits.\n
\n --relaxed\tIgnores bad paths unless they're all bad but warns\
\n\t\tyou about them. Ignores in-appropriate rename switch\
\n\t\twithout exiting. This is default behavior. You can \
\n\t\tmake strict the default behavior by editing the \
\n\t\tCP script and setting: \n
\n\t\teasy_going=false.\n
\n --help-all\tShows help specific to cp (in addition to CP)."
cp_hlp="\n\nRegular cp command's switches will still work when using CP.\
\nHere is the help out of the original cp command... \
\n\n===============================================================================\
\n cp specific help: \
\n===============================================================================\n"
outro1="\n******************************************************************************\
\n******************************************************************************\
\n******************************************************************************\
\n USE THIS SCRIPT WITH CARE, TYPOS WILL GIVE YOU PROBLEMS...\
\n******************************************************************************\
\n******************************* HIT q TO EXIT ********************************\
\n******************************************************************************"#count and classify arguments that were inputed into script, output help message if neededwhile true;doeval input="\$$n"
in_=${input::1}if[-z "$input"-a $n =1];then input="--help";fiif["$input"="-h"-o "$input"="--help"-o "$input"="-?"-o "$input"="--help-all"];thenif["$input"="--help-all"];then
echo -e "$help"$cp_hlp >/tmp/cp.hlp
cp --help >>/tmp/cp.hlp
echo -e "$outro1">>/tmp/cp.hlp
cat /tmp/cp.hlp|less
cat /tmp/cp.hlp
rm /tmp/cp.hlp
else
echo -e "$help""$outro1"|less
echo -e "$help""$outro1"fi
exit
fiif[-z "$input"];then
count_i=$(expr $count_i -1)# remember, last item is destination and it's not included in coundbreakelif["$in_"="-"];then
count_s=$(expr $count_s +1)else
count_i=$(expr $count_i +1)fi
n=$(expr $n +1)done#error condition: no items to copy or no destinationif[ $count_i -lt 0];then
echo "Error: You haven't listed any items for copying. Exiting."# you didn't put any items for copyingelif[ $count_i -lt 1];then
echo "Error: Copying usually involves a destination. Exiting."# you put one item and no destinationfi#reset the counter and grab content of arguments, aka: switches and item paths
n=1while true;doeval input="\$$n"#input=$1,$2,$3,etc...
in_=${input::1}#first letter of $inputif["$in_"="-"];thenif["$input"="--rename"];then
rename=true #my custom switcheselif["$input"="--strict"];then
easy_going=false #exit script if even one of the non-destinations item is not foundelif["$input"="--relaxed"];then
easy_going=true #continue script if at least one of the non-destination items is foundelif["$input"="--quiet"];then
verbal=""else#m=$(expr $m + 1);eval switch$m="$input" #input is a switch, if it's not one of the above, assume it belongs to cp.
switch_list="$switch_list \"$input\""fielif![-z "$input"];then#if it's not a switch and input is not empty, it's a path
i=$(expr $i +1)if[!-f "$input"-a !-d "$input"-a "$i"-le "$count_i"];then
err=$(expr $err +1); error_list="$error_list\npath does not exit: \"b\""elseif["$i"-le "$count_i"];theneval item$i="$input"
item_list="$item_list \"$input\""else
destination="$input"#destination is last items enteredfifielse
i=0
m=0
n=1breakfi
n=$(expr $n +1)done#error condition: some or all item(s) being copied don't exist. easy_going: continue if at least one item exists, warn about rest, not easy_going: exit.#echo "err=$err count_i=$count_i"if["$easy_going"!= true -a $err -gt 0-a $err != $count_i ];then
echo "Some of the paths you entered are incorrect. Script is running in strict mode and will therefore exit."
echo -e "Bad Paths: $err $error_list"
exit
fiif[ $err = $count_i ];then
echo "ALL THE PATHS you have entered are incorrect! Exiting."
echo -e "Bad Paths: $err $error_list"fi#one item to one destination:#------------------------------#assumes that destination is folder, it does't exist, it will create it. (so copying /a/b/c/d/firefox to /e/f/firefox will result in /e/f/firefox/firefox#if -rename switch is given, will assume that the top element of destination path is the new name for the the item being given.#multi-item to single destination:#------------------------------#assumes destination is a folder, gives error if it exists and it's a file. -rename switch will be ignored.#ERROR CONDITIONS: # - multiple items being sent to a destination and it's a file.# - if -rename switch was given and multiple items are being copied, rename switch will be ignored (easy_going). if not easy_going, exit.# - rename option but source is folder, destination is file, exit.# - rename option but source is file and destination is folder. easy_going: option ignored.if[-f "$destination"];thenif[ $count_i -gt 1];then
echo "Error: You've selected a single file as a destination and are copying multiple items to it. Exiting."; exit
elif[-d "$item1"];then
echo "Error: Your destination is a file but your source is a folder. Exiting."; exit
fifiif["$rename"= true ];thenif[ $count_i -gt 1];thenif[ $easy_going = true ];then
echo "Warning: you choose the rename option but are copying multiple items. Ignoring Rename option. Continuing."else
echo "Error: you choose the rename option but are copying multiple items. Script running in strict mode. Exiting."; exit
fielif[-d "$destination"-a -f "$item1"];then
echo -n "Warning: you choose the rename option but source is a file and destination is a folder with the same name. "if[ $easy_going = true ];then
echo "Ignoring Rename option. Continuing."else
echo "Script running in strict mode. Exiting."; exit
fielse
dest_jr=$(dirname "$destination")if[-d "$destination"];then item_list="$item1/*";fi
mkdir -p "$dest_jr"fielse
mkdir -p "$destination"fieval cp $switch_list $verbal $item_list "$destination"
cp_err="$?"if["$cp_err"!=0];then
echo -e "Something went wrong with the copy operation. \nExit Status: $cp_err"else
echo "Copy operation exited with no errors."fi
exit
Dies ist vielleicht ein Overkill, aber ziemlich effizient, funktioniert wie erwartet, danke, guter Herr.
Xedret
2
cp hat mehrere Verwendungen:
$ cp --help
Usage: cp [OPTION]...[-T] SOURCE DEST
or: cp [OPTION]... SOURCE... DIRECTORY
or: cp [OPTION]...-t DIRECTORY SOURCE...Copy SOURCE to DEST, or multiple SOURCE(s) to DIRECTORY.
@ AndyRoss Antwort funktioniert für die
cp SOURCE DEST
Stil cp, aber macht das Falsche, wenn Sie die verwenden
cp SOURCE... DIRECTORY/
Stil von cp.
Ich denke, dass "DEST" ohne einen abschließenden Schrägstrich in dieser Verwendung mehrdeutig ist (dh wo das Zielverzeichnis noch nicht existiert), weshalb möglicherweise cpnie eine Option dafür hinzugefügt wurde.
Hier ist meine Version dieser Funktion, die einen abschließenden Schrägstrich im Zielverzeichnis erzwingt:
Wie oben von help_asap und spongeman vorgeschlagen, können Sie mit dem Befehl 'install' Dateien in vorhandene Verzeichnisse kopieren oder neue Zielverzeichnisse erstellen, sofern diese noch nicht vorhanden sind.
Option 1
install -D filename some/deep/directory/filename
kopiert die Datei in ein neues oder vorhandenes Verzeichnis und erteilt dem Dateinamen standardmäßig 755 Berechtigungen
Option 2
install -D filename -m640 some/deep/directory/filename
gemäß Option 1, gibt jedoch Dateinamen 640-Berechtigungen.
Option 3
install -D filename -m640 -t some/deep/directory/
gemäß Option 2, zielt jedoch auf den Dateinamen im Zielverzeichnis ab, sodass der Dateiname nicht sowohl im Quell- als auch im Zielverzeichnis geschrieben werden muss.
Option 4
install -D filena* -m640 -t some/deep/directory/
gemäß Option 3, verwendet jedoch einen Platzhalter für mehrere Dateien.
Es funktioniert gut in Ubuntu und kombiniert zwei Schritte (Verzeichniserstellung, dann Dateikopie) in einem einzigen Schritt.
Dies ist sehr spät, aber es kann einem Anfänger irgendwo helfen. Wenn Sie Ordner automatisch erstellen müssen, sollte rsync Ihr bester Freund sein. rsync / path / to / sourcefile / path / to / tragetdir / thatdoestexist /
cp
(wie von Paul Whipp beantwortet), aber sie ist nicht so allgemein wie vom OP angefordert. Es kann kopierena/foo/bar/file
zu ,b/foo/bar/file
aber es kann nicht kopierenfile
zub/foo/bar/file
. (dh es funktioniert nur, um übergeordnete Verzeichnisse zu erstellen, die bereits im Fall der ersten Datei vorhanden waren, aber es können keine beliebigen Verzeichnisse erstellt werden)Antworten:
(Es gibt keine solche Option für
cp
).quelle
test -d
: istmkdir -p
immer noch erfolgreich, auch wenn das Verzeichnis bereits existiert.mkdir
ist ein eingebautes in BusyBox;)$d
ist eine Variable, die vermutlich das betreffende Verzeichnis enthält. Ich meine, wenn Sie es dreimal wiederholen müssen, werden Sie es wahrscheinlich zuerst der Variablen zuweisen.Wenn beide der folgenden Aussagen zutreffen:
cp
(und nicht beispielsweise die Mac-Version) unddann können Sie dies mit der
--parents
Flagge von tuncp
. Von der Infoseite (sichtbar unter http://www.gnu.org/software/coreutils/manual/html_node/cp-invocation.html#cp-invocation oder mitinfo cp
oderman cp
):Beispiel:
quelle
macports
, können Sie coreutils und seine installierengcp
.Kurze Antwort
So kopieren
myfile.txt
zu/foo/bar/myfile.txt
verwenden:Wie funktioniert das?
Da dies einige Komponenten enthält, werde ich Schritt für Schritt die gesamte Syntax behandeln.
Das im POSIX-Standard angegebene Dienstprogramm mkdir erstellt Verzeichnisse. Das Argument, pro der Dokumentation, wird dazu führen , mkdir zu
-p
dass bedeutet , wenn Sie anrufen
mkdir -p /foo/bar
, mkdir schaffen wird/foo
und/foo/bar
wenn/foo
keine vorhanden ist. (Ohne-p
wird stattdessen ein Fehler ausgegeben.Der
&&
Listenoperator, wie im POSIX-Standard (oder im Bash-Handbuch, wenn Sie dies bevorzugen) dokumentiert , hat den Effekt, dass ercp myfile.txt $_
nur ausgeführt wird, wenn ermkdir -p /foo/bar
erfolgreich ausgeführt wird. Dies bedeutet, dass dercp
Befehl nicht versucht, ausgeführt zu werden, wenn ermkdir
aus einem der vielen Gründe fehlschlägt .Schließlich ist das, das
$_
wir als zweites Argument übergeben,cp
ein "spezieller Parameter", der nützlich sein kann, um zu vermeiden, dass lange Argumente (wie Dateipfade) wiederholt werden, ohne dass sie in einer Variablen gespeichert werden müssen. Gemäß dem Bash-Handbuch gilt Folgendes:In diesem Fall haben
/foo/bar
wir das weitergegebenmkdir
. Dercp
Befehl wird also erweitert und in das neu erstellte Verzeichniscp myfile.txt /foo/bar
kopiert .myfile.txt
/foo/bar
Beachten Sie, dass
$_
ist nicht Teil des POSIX - Standard , so dass theoretisch eine Unix - Variante könnte eine Schale hat , die nicht dieses Konstrukt nicht unterstützt. Ich kenne jedoch keine modernen Muscheln, die nicht unterstützt werden$_
. sicherlich tun es Bash, Dash und zsh alle.Ein letzter Hinweis: Der Befehl, den ich zu Beginn dieser Antwort gegeben habe, setzt voraus, dass Ihre Verzeichnisnamen keine Leerzeichen enthalten. Wenn Sie mit Namen mit Leerzeichen arbeiten, müssen Sie sie so zitieren, dass die verschiedenen Wörter werden nicht als unterschiedliche Argumente zu
mkdir
oder behandeltcp
. Ihr Befehl würde also tatsächlich so aussehen:quelle
Eine so alte Frage, aber vielleicht kann ich eine alternative Lösung vorschlagen.
Mit dem
install
Programm können Sie Ihre Datei kopieren und den Zielpfad "on the fly" erstellen.Es sind jedoch einige Aspekte zu berücksichtigen:
Sie können die Nummer 2 einfach ändern, indem Sie die
-m
Option zum Festlegen von Berechtigungen für die Zieldatei hinzufügen (Beispiel:-m 664
Erstellt die Zieldatei mit Berechtigungenrw-rw-r--
, genau wie das Erstellen einer neuen Datei mittouch
).Und hier ist es die schamlose Verbindung zu der Antwort, von der ich inspiriert wurde =)
quelle
755
(rwxr-xr-x
) Berechtigungen erstellt, was wahrscheinlich nicht erwünscht ist. Sie können etwas anderes mit dem angeben-m
Schalter, aber ich konnte nicht einen Weg finden nur halten Sie die Dateiberechtigungen :(Shell-Funktion, die macht, was Sie wollen, und sie als "Begräbnis" -Kopie bezeichnet, weil sie ein Loch für die Datei gräbt, in der sie leben soll:
quelle
dirname $2
zu$2
als Argument zitierendirname
. Wiemkdir -p "$(dirname "$2")"
. Ohne diese Angabe$2
incp
nützt nichts;)dirname "$2"
&& cp -r "$ 1" "$ 2"; Beachten Sie, dass die Backticksdirname $2
nicht angezeigt werden, da SO sie als Codemarkierungen analysiert.Hier ist eine Möglichkeit, dies zu tun:
dirname
gibt Ihnen das übergeordnete Element des Zielverzeichnisses oder der Zieldatei. mkdir -p `dirname ...` erstellt dann dieses Verzeichnis und stellt sicher, dass beim Aufrufen von cp -r das richtige Basisverzeichnis vorhanden ist.Der Vorteil dieser Übereltern besteht darin, dass sie für den Fall funktionieren, dass das letzte Element im Zielpfad ein Dateiname ist.
Und es wird unter OS X funktionieren.
quelle
install -D file -m 644 -t /path/to/copy/file/to/is/very/deep/there
quelle
there
die endgültige Datei und nicht das endgültige Unterverzeichnis ist.Bei allem Respekt für die obigen Antworten bevorzuge ich die Verwendung von rsync wie folgt:
Beispiel:
quelle
rsync
ist vorhersehbarer alscp
. Wenn ich zum Beispiel möchte,cp /from/somedir /to-dir
verhält sich cp anders, wenn/to-dir
es bereits existiert: Wenn es/to-dir
existiert,cp
wird erstellt/to-dir/some-dir
, andernfalls wird nur der Inhalt von/from/somedir
platziert/to-dir
. Verhältrsync
sich jedoch gleich für den Fall,/to-dir/some-dir
dass immer erstellt wird.Nur um fortzufahren und eine vollständige Arbeitslösung in einer Zeile zu geben. Seien Sie vorsichtig, wenn Sie Ihre Datei umbenennen möchten. Geben Sie eine Möglichkeit an, einen sauberen Verzeichnispfad zu mkdir bereitzustellen. $ fdst kann eine Datei oder ein Verzeichnis sein. Der nächste Code sollte auf jeden Fall funktionieren.
oder bash spezifisch
quelle
Fügen Sie einfach Folgendes in Ihre .bashrc ein und optimieren Sie es bei Bedarf. Funktioniert in Ubuntu.
Beispiel: Wenn Sie die 'Test'-Datei in das Zielverzeichnis' d 'Use kopieren möchten,
mkcp prüft zunächst, ob das Zielverzeichnis vorhanden ist oder nicht. Wenn nicht, erstellen Sie es und kopieren Sie die Quelldatei / das Quellverzeichnis.
quelle
mkdir -p
. Es wird erfolgreich sein, auch wenn es bereits existiert.Das macht es für mich
quelle
man cp
:-R If source_file designates a directory, cp copies the directory and the entire subtree connected at that point.
Ich habe ein Support-Skript für cp namens CP (Note Großbuchstaben) geschrieben, das genau dies tun soll. Das Skript prüft den von Ihnen eingegebenen Pfad auf Fehler (mit Ausnahme des letzten, der das Ziel ist). Wenn alles in Ordnung ist, führt es einen mkdir -p-Schritt aus, um den Zielpfad zu erstellen, bevor die Kopie gestartet wird. Zu diesem Zeitpunkt übernimmt das reguläre Dienstprogramm cp und alle Schalter, die Sie mit CP verwenden (wie -r, -p, -rpL werden direkt an cp weitergeleitet). Bevor Sie mein Skript verwenden, müssen Sie einige Dinge verstehen.
CP hat nicht den Luxus, sich an bestehenden Pfaden zu orientieren, daher muss es einige sehr feste Verhaltensmuster haben. CP geht davon aus, dass das zu kopierende Element im Zielpfad abgelegt wird und nicht das Ziel selbst ist (auch bekannt als umbenannte Kopie der Quelldatei / des Quellordners). Bedeutung:
Dieses Standard-CP-Verhalten kann mit dem Schalter "--rename" geändert werden. In diesem Fall wird davon ausgegangen, dass
Einige abschließende Hinweise: Wie bei cp kann CP mehrere Elemente gleichzeitig kopieren, wobei der zuletzt aufgeführte Pfad als Ziel angenommen wird. Es kann auch Pfade mit Leerzeichen verarbeiten, solange Sie Anführungszeichen verwenden.
CP überprüft die von Ihnen eingegebenen Pfade und stellt sicher, dass sie vorhanden sind, bevor Sie die Kopie erstellen. Im strengen Modus (verfügbar über den Schalter --strict) müssen alle zu kopierenden Dateien / Ordner vorhanden sein, da sonst keine Kopie erfolgt. Im entspannten Modus (--relaxed) wird der Kopiervorgang fortgesetzt, wenn mindestens eines der von Ihnen aufgelisteten Elemente vorhanden ist. Der entspannte Modus ist die Standardeinstellung. Sie können den Modus vorübergehend über die Schalter oder dauerhaft ändern, indem Sie die Variable easy_going am Anfang des Skripts festlegen.
So installieren Sie es:
Führen Sie in einem Nicht-Root-Terminal Folgendes aus:
Fügen Sie in gedit das CP-Dienstprogramm ein und speichern Sie:
quelle
cp
hat mehrere Verwendungen:@ AndyRoss Antwort funktioniert für die
Stil
cp
, aber macht das Falsche, wenn Sie die verwendenStil von
cp
.Ich denke, dass "DEST" ohne einen abschließenden Schrägstrich in dieser Verwendung mehrdeutig ist (dh wo das Zielverzeichnis noch nicht existiert), weshalb möglicherweise
cp
nie eine Option dafür hinzugefügt wurde.Hier ist meine Version dieser Funktion, die einen abschließenden Schrägstrich im Zielverzeichnis erzwingt:
quelle
Hatte gerade das gleiche Problem. Mein Ansatz war es, die Dateien einfach so in ein Archiv zu tarieren:
tar cf your_archive.tar file1 /path/to/file2 path/to/even/deeper/file3
tar speichert die Dateien automatisch in der entsprechenden Struktur im Archiv. Wenn du läufst
tar xf your_archive.tar
Die Dateien werden in die gewünschte Verzeichnisstruktur extrahiert.
quelle
Wie oben von help_asap und spongeman vorgeschlagen, können Sie mit dem Befehl 'install' Dateien in vorhandene Verzeichnisse kopieren oder neue Zielverzeichnisse erstellen, sofern diese noch nicht vorhanden sind.
Option 1
install -D filename some/deep/directory/filename
kopiert die Datei in ein neues oder vorhandenes Verzeichnis und erteilt dem Dateinamen standardmäßig 755 Berechtigungen
Option 2
install -D filename -m640 some/deep/directory/filename
gemäß Option 1, gibt jedoch Dateinamen 640-Berechtigungen.
Option 3
install -D filename -m640 -t some/deep/directory/
gemäß Option 2, zielt jedoch auf den Dateinamen im Zielverzeichnis ab, sodass der Dateiname nicht sowohl im Quell- als auch im Zielverzeichnis geschrieben werden muss.
Option 4
install -D filena* -m640 -t some/deep/directory/
gemäß Option 3, verwendet jedoch einen Platzhalter für mehrere Dateien.
Es funktioniert gut in Ubuntu und kombiniert zwei Schritte (Verzeichniserstellung, dann Dateikopie) in einem einzigen Schritt.
quelle
Dies ist sehr spät, aber es kann einem Anfänger irgendwo helfen. Wenn Sie Ordner automatisch erstellen müssen, sollte rsync Ihr bester Freund sein. rsync / path / to / sourcefile / path / to / tragetdir / thatdoestexist /
quelle
Dies könnte funktionieren, wenn Sie die richtige Art von haben
rsync
.quelle
Kopieren Sie von der Quelle in einen nicht vorhandenen Pfad
HINWEIS: Dieser Befehl kopiert alle Dateien
cp –r
zum Kopieren aller Ordner und ihres Inhalts$_
Arbeit als Ziel, das im letzten Befehl erstellt wurdequelle
Einfach
sollte den Trick machen.
quelle
Nehmen wir an, Sie machen so etwas
Dabei sind A / B / C / D Verzeichnisse, die noch nicht existieren
Eine mögliche Lösung ist wie folgt
Ich hoffe, das hilft!
quelle