La réponse acceptée est fausse (il existe une telle option pour cp). Voir la deuxième réponse de Paul Whipp.
Ronenz
1
@Ronenz, je suis d'accord qu'il existe une option qui mérite d'être mentionnée dans GNU cp(comme l'a répondu Paul Whipp), mais elle n'est pas aussi générale que l'OP demandé. Il peut copier a/foo/bar/filevers b/foo/bar/filemais il ne peut pas copier filevers b/foo/bar/file. (c'est-à-dire que cela ne fonctionne que pour créer des répertoires parents qui existaient déjà dans le cas du premier fichier, mais il ne peut pas créer de répertoires arbitraires)
Sudo Bash
Cela ressemble à une belle demande de fonctionnalité pour cp. Y a-t-il une chance que nous puissions obtenir un tel commutateur de ligne de commande dans un avenir proche?
Je ne pense pas que vous ayez besoin de test -d: mkdir -préussit toujours même si le répertoire existe déjà.
éphémère
oups. Mais alors, test peut être un bash intégré (surtout s'il est écrit comme [[-d "$ d"]]]) et mkdir ne peut pas ;-)
Michael Krelin - pirate
1
mkdirest une fonction intégrée dans BusyBox;)
éphémère
7
@holms, $dest une variable qui contient vraisemblablement le répertoire en question. Je veux dire, si vous devez le répéter trois fois, vous êtes susceptible de l'attribuer à la variable en premier.
Michael Krelin - hacker
237
Si les deux conditions suivantes sont vraies:
Vous utilisez la version GNU de cp(et non, par exemple, la version Mac), et
Vous copiez à partir d'une structure de répertoire existante et vous avez juste besoin de la recréer
--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.
Exemple:
/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
Cela ne fonctionne pas sur Mac OS X, donc je suppose que c'est spécifique à Linux.
olt
7
Je dirais spécifique au gnu. Si vous en avez, macportsvous pouvez installer coreutils et son gcp.
Michael Krelin - hacker
16
Man, Linux a tout
Ziggy
19
J'ai l'impression que c'est la réponse à une question légèrement différente, même si c'est la réponse que je cherchais (et donc celle que j'ai surévaluée). Je suppose que c'est la solution en supposant que vous vouliez que les répertoires parents de destination soient les mêmes que les répertoires parents d'origine, ce qui est probablement le cas d'utilisation dans lequel la plupart des gens lisent ceci sont intéressants.
David Winiecki
7
Cela suppose que le répertoire «bar» existe déjà, mais la question d'origine implique comment créer automatiquement «bar» lorsqu'il est fourni comme destination et qu'il n'existe pas déjà. La réponse à cela est fournie par @ MichaelKrelin-hacker.
thdoan
69
Réponse courte
Pour copier myfile.txtvers /foo/bar/myfile.txt, utilisez:
mkdir -p /foo/bar && cp myfile.txt $_
Comment cela marche-t-il?
Il y a quelques composants à cela, donc je vais couvrir toute la syntaxe étape par étape.
Créer tous les composants de chemin d'accès intermédiaires manquants
ce qui signifie que lors de l'appel mkdir -p /foo/bar, mkdir créera /fooet/foo/bar s'il /foon'existe pas déjà. (Sans -p, cela générera une erreur.
L' &&opérateur de liste, tel que documenté dans la norme POSIX (ou le manuel Bash si vous préférez), a l'effet qui cp myfile.txt $_n'est exécuté que s'il mkdir -p /foo/bars'exécute avec succès. Cela signifie que la cpcommande n'essaiera pas de s'exécuter en cas d' mkdiréchec pour l' une des nombreuses raisons pour lesquelles elle pourrait échouer .
Enfin, le $_second argument que nous passons cpest un "paramètre spécial" qui peut être pratique pour éviter de répéter de longs arguments (comme des chemins de fichier) sans avoir à les stocker dans une variable. Selon le manuel de Bash , il:
se développe jusqu'au dernier argument de la commande précédente
Dans ce cas, c'est le /foo/barnous sommes passés à mkdir. Ainsi, la cpcommande se développe vers cp myfile.txt /foo/bar, qui copie myfile.txtdans le /foo/barrépertoire nouvellement créé .
Notez que cela ne$_ fait pas partie de la norme POSIX , donc théoriquement une variante Unix pourrait avoir un shell qui ne prend pas en charge cette construction. Cependant, je ne connais aucun obus moderne qui ne supporte pas $_; certainement Bash, Dash et zsh le font tous.
Une dernière note: la commande que j'ai donnée au début de cette réponse suppose que vos noms de répertoires n'ont pas d'espaces. Si vous avez affaire à des noms avec des espaces, vous devrez les citer entre eux afin que les différents mots ne sont pas traités comme des arguments différents de mkdirou cp. Donc, votre commande ressemblerait en fait à:
mkdir -p "/my directory/name with/spaces"&& cp "my filename with spaces.txt""$_"
En plus: Je suis généralement déçu par le manque de détails dans les questions sur les commandes shell Bash ou Unix sur Stack Overflow, qui jettent souvent une ligne compliquée et extrêmement dense qui est difficile à décocher si vous n'êtes pas déjà un assistant Unix. J'ai essayé d'aller à l'extrême opposé ici et d'expliquer tous les détails de la syntaxe et de créer un lien vers les endroits appropriés pour trouver de la documentation sur le fonctionnement de ces éléments. J'espère que cela aide au moins certaines personnes. En outre, le crédit est dû: j'ai annulé cette approche à partir de cette réponse à une question en double: stackoverflow.com/a/14085147/1709587
Mark Amery
Je n'ai jamais vu $ _ auparavant. à quoi cela fait-il référence? le dossier utilisé dans la dernière commande?
thebunnyrules
9
@thebunnyrules Mais ... mais ... il y a un "Comment ça marche?" section de ma réponse qui contient littéralement plusieurs paragraphes spécifiquement consacrés à la question que vous venez de poser. Il se sent ignoré et mal aimé. :(
Mark Amery
Désolé pour ça. Vous avez absolument raison. Je savais déjà tout le reste dans votre réponse, je l'ai donc rapidement parcourue. J'aurais dû le lire plus attentivement.
thebunnyrules
Wow, vous avez vraiment mis beaucoup de travail dans cette réponse ... Merci pour cela. C'était agréable d'en savoir plus sur: $ _. Je peux me voir l'utiliser un peu à partir de maintenant. J'ai écrit un script pour automatiser l'ensemble du processus et mis en place dans ce fil. Essayez-le, vous aimerez peut-être: stackoverflow.com/questions/1529946/…
thebunnyrules
39
Une telle vieille question, mais je peux peut-être proposer une solution alternative.
Vous pouvez utiliser le installprogramme pour copier votre fichier et créer le chemin de destination "à la volée".
Il y a cependant certains aspects à prendre en considération:
vous devez également spécifier le nom du fichier de destination , pas seulement le chemin de destination
le fichier de destination sera exécutable (au moins, d'après ce que j'ai vu de mes tests)
Vous pouvez facilement modifier le # 2 en ajoutant l' -moption pour définir des autorisations sur le fichier de destination (exemple: -m 664créera le fichier de destination avec des autorisations rw-rw-r--, tout comme la création d'un nouveau fichier avec touch).
N'a pas vraiment fonctionné pour mon utilisation mais astuce cool! Je m'en souviendrai.
thebunnyrules
notez que cette commande crée les fichiers de destination avec les autorisations 755( rwxr-xr-x), ce qui n'est probablement pas souhaité. vous pouvez spécifier autre chose avec le -mcommutateur, mais je n'ai pas pu trouver un moyen de simplement conserver les autorisations sur les fichiers :(
törzsmókus
19
Fonction Shell qui fait ce que vous voulez, en l'appelant une copie "enterrée" car elle creuse un trou dans lequel le fichier doit vivre:
Vous devriez avoir des guillemets autour du dirname $2trop
Tarnay Kálmán
4
@ Kalmi, pour une citation correcte, vous voudrez également citer $2comme argument dirname. Comme mkdir -p "$(dirname "$2")". Sans cette citation $2en cpest inutile;)
Michael Krelin - hacker
3
Notez que cette réponse suppose que $ 2 n'est pas déjà le répertoire cible, sinon vous voudriez simplement "mkdir -p" $ 2 "&& cp" $ 1 "" $ 2 "comme corps de fonction
user467257
Je pense que cela a un bug, comme le souligne @ user467257. Je ne pense pas que ce soit réparable, car $ 2 est ambigu entre le répertoire cible et le fichier cible dans ce scénario. J'ai publié une réponse alternative qui résout ce problème.
Rich
@ Rich, je ne suis pas d'accord que ce n'est pas réparable. Ce qui suit fonctionne très bien pour les fichiers et les répertoires: mkdir -p dirname "$2"&& cp -r "$ 1" "$ 2"; Notez que les backticks autour dirname $2ne s'affichent pas car SO les analyse en tant que marqueurs de code.
dirnamevous donnera le parent du répertoire ou du fichier de destination. mkdir -p `dirname ...` créera alors ce répertoire en s'assurant que lorsque vous appelez cp -r le répertoire de base correct est en place.
L'avantage de ce sur-parent est qu'il fonctionne dans le cas où le dernier élément du chemin de destination est un nom de fichier.
en fait, ce n'est pas du tout la même chose. sa vous oblige à passer le nom de fichier deux fois (d'où l'indicateur '-t') et il définit les bits d'exécution sur le fichier (d'où l'exemple '-m'). sa ne devrait pas être la meilleure réponse, car elle ne répond pas réellement à la question - contrairement à la mienne.
Spongman
1
Cela fonctionne pour un seul fichier. Prenez simplement en compte qu'il theres'agit du fichier final et non du sous-répertoire final.
kvantour
6
avec tout mon respect pour les réponses ci-dessus, je préfère utiliser rsync comme suit:
$ rsync -a directory_name /path_where_to_inject_your_directory/
J'ai essayé et j'obtiens ce résultat: rsync -a bull / some / hoop / ti / doop / ploop RESULTAT rsync: mkdir "/ some / hoop / ti / doop / ploop" a échoué: aucun fichier ou répertoire (2) erreur rsync : erreur dans le fichier IO (code 11) sur main.c (675) [Receiver = 3.1.2]
Si je comprends bien votre suggestion, vous proposez que je spécifie un chemin complet vers la source aka use: "$ (pwd) / bull" dans ma commande au lieu du nom de fichier: bull? Le truc, c'est que rsync crée le répertoire de destination, pas la source (bull). Il me semble que rsync utilise un simple mkdir et non un mkdir -p.
thebunnyrules
1
Très utile d'ailleurs, je pourrais commencer à l'utiliser dans mes scripts. Merci de le recommander.
thebunnyrules
1
rsync est plus prévisible que cp. Par exemple, si je souhaite cp /from/somedir /to-diralors cp se comporte différemment s'il /to-direxiste déjà: s'il /to-direxiste, alors cpcréera /to-dir/some-dir, sinon juste le contenu de /from/somedirsera placé dans /to-dir. Cependant, rsyncse comporte de la même façon au cas où, c'est-à-dire, /to-dir/some-dirsera toujours créé.
JoeAC
5
Juste pour reprendre et donner une solution de travail complète, en une seule ligne. Soyez prudent si vous souhaitez renommer votre fichier, vous devez inclure un moyen de fournir un chemin de répertoire propre à mkdir. $ fdst peut être un fichier ou un dir. Le code suivant devrait fonctionner dans tous les cas.
Merci! Voilà ce dont j'avais besoin. Dans mon cas, je ne sais pas si la destination a un répertoire ou non et si le répertoire existe ou non, donc ce code me donne le répertoire parent que je peux ensuite créer en toute sécurité s'il n'existe pas
xbmono
4
Ajoutez simplement ce qui suit dans votre .bashrc, ajustez si vous en avez besoin. Fonctionne dans Ubuntu.
mkcp(){
test -d "$2"|| mkdir -p "$2"
cp -r "$1""$2"}
Par exemple, si vous souhaitez copier le fichier "test" dans le répertoire de destination "d" Utiliser,
mkcp test a/b/c/d
mkcp vérifiera d'abord si le répertoire de destination existe ou non, sinon créez-le et copiez le fichier / répertoire source.
Comme d'autres ont commenté l'autre réponse, vous n'avez pas besoin de tester si le répertoire existe avant d'appeler mkdir -p. Il réussira même s'il existe déjà.
Se mettre d'accord. Dans man cp:-R If source_file designates a directory, cp copies the directory and the entire subtree connected at that point.
borracciaBlu
3
J'ai écrit un script de support pour cp, appelé CP (note majuscules) qui est destiné à faire exactement cela. Le script vérifiera les erreurs dans le chemin que vous avez mis (sauf le dernier qui est la destination) et si tout va bien, il fera une étape mkdir -p pour créer le chemin de destination avant de commencer la copie. À ce stade, l'utilitaire cp normal prend le relais et tous les commutateurs que vous utilisez avec CP (comme -r, -p, -rpL sont dirigés directement vers cp). Avant d'utiliser mon script, vous devez comprendre certaines choses.
toutes les informations ici sont accessibles en utilisant CP --help. CP --help-all inclut les commutateurs cp de.
cp normal ne fera pas la copie s'il ne trouve pas le chemin de destination. Vous n'avez pas un tel filet de sécurité pour les fautes de frappe avec CP. Votre destination sera créée, donc si vous mal orthographiez votre destination en tant que / usrr / share / icons ou / usr / share / icon, c'est ce qui va être créé.
cp normal a tendance à modéliser son comportement sur le chemin existant: cp / a / b / c / d variera selon que d existe ou non. si d est un dossier existant, cp copiera b dans celui-ci, créant / c / d / b. Si d n'existe pas, b sera copié dans c et renommé en d. Si d existe mais est un fichier et b est un fichier, il sera écrasé par la copie de b. Si c n'existe pas, cp ne fait pas la copie et quitte.
Le CP n'a pas le luxe de s'inspirer des chemins existants, il doit donc avoir des schémas de comportement très fermes. CP suppose que l'élément que vous copiez est déposé dans le chemin de destination et n'est pas la destination elle-même (c'est-à-dire une copie renommée du fichier / dossier source). Sens:
"CP / a / b / c / d" se traduira par / c / d / b si d est un dossier
"CP / a / b / c / b" se traduira par / c / b / b si b dans / c / b est un dossier.
Si b et d sont tous deux des fichiers: CP / a / b / c / d donnera / c / d (où d est une copie de b). Idem pour CP / a / b / c / b dans les mêmes circonstances.
Ce comportement CP par défaut peut être modifié avec le commutateur "--rename". Dans ce cas, on suppose que
"CP --rename / a / b / c / d" copie b dans / c et renomme la copie en d.
Quelques notes de clôture: Comme avec cp, CP peut copier plusieurs éléments à la fois, le dernier chemin répertorié étant supposé être la destination. Il peut également gérer des chemins avec des espaces tant que vous utilisez des guillemets.
CP vérifiera les chemins que vous avez mis et s'assurera qu'ils existent avant de faire la copie. En mode strict (disponible via l'option --strict), tous les fichiers / dossiers copiés doivent exister ou aucune copie n'a lieu. En mode détendu (--relaxed), la copie continuera si au moins un des éléments que vous avez répertoriés existe. Le mode détendu est le mode par défaut, vous pouvez changer le mode temporairement via les commutateurs ou de façon permanente en définissant la variable easy_going au début du script.
Dans gedit, collez l'utilitaire CP et enregistrez:
#!/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
C'est peut-être exagéré, mais assez efficace, fonctionne comme prévu, merci bon monsieur.
Xedret
2
cp a de multiples usages:
$ 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.
La réponse de @ AndyRoss fonctionne pour le
cp SOURCE DEST
style de cp, mais fait la mauvaise chose si vous utilisez le
cp SOURCE... DIRECTORY/
style de cp.
Je pense que "DEST" est ambigu sans barre oblique dans cet usage (c'est-à-dire où le répertoire cible n'existe pas encore), c'est peut-être pourquoi cpn'a jamais ajouté une option pour cela.
Voici donc ma version de cette fonction qui applique une barre oblique de fin sur le répertoire dest:
Comme suggéré ci-dessus par help_asap et spongeman, vous pouvez utiliser la commande 'install' pour copier des fichiers dans des répertoires existants ou créer de nouveaux répertoires de destination s'ils n'existent pas déjà.
L'option 1
install -D filename some/deep/directory/filename
copie le fichier dans un répertoire nouveau ou existant et donne les autorisations 755 par défaut au nom de fichier
Option 2
install -D filename -m640 some/deep/directory/filename
selon l'option 1 mais donne 640 autorisations de nom de fichier.
Option 3
install -D filename -m640 -t some/deep/directory/
selon l'option 2, mais cible le nom de fichier dans le répertoire cible de sorte que le nom de fichier n'a pas besoin d'être écrit à la fois dans la source et dans la cible.
Option 4
install -D filena* -m640 -t some/deep/directory/
selon l'option 3, mais utilise un caractère générique pour plusieurs fichiers.
Il fonctionne bien dans Ubuntu et combine deux étapes (création de répertoire puis copie de fichier) en une seule étape.
C'est très tard, mais cela peut aider une recrue quelque part. Si vous devez créer automatiquement des dossiers, rsync devrait être votre meilleur ami. rsync / path / to / sourcefile / path / to / tragetdir / thatdoestexist /
cp
(comme l'a répondu Paul Whipp), mais elle n'est pas aussi générale que l'OP demandé. Il peut copiera/foo/bar/file
versb/foo/bar/file
mais il ne peut pas copierfile
versb/foo/bar/file
. (c'est-à-dire que cela ne fonctionne que pour créer des répertoires parents qui existaient déjà dans le cas du premier fichier, mais il ne peut pas créer de répertoires arbitraires)Réponses:
(il n'y a pas une telle option pour
cp
).la source
test -d
:mkdir -p
réussit toujours même si le répertoire existe déjà.mkdir
est une fonction intégrée dans BusyBox;)$d
est une variable qui contient vraisemblablement le répertoire en question. Je veux dire, si vous devez le répéter trois fois, vous êtes susceptible de l'attribuer à la variable en premier.Si les deux conditions suivantes sont vraies:
cp
(et non, par exemple, la version Mac), etalors vous pouvez le faire avec le
--parents
drapeau decp
. Depuis la page d'informations (consultable sur http://www.gnu.org/software/coreutils/manual/html_node/cp-invocation.html#cp-invocation ou avecinfo cp
ouman cp
):Exemple:
la source
macports
vous pouvez installer coreutils et songcp
.Réponse courte
Pour copier
myfile.txt
vers/foo/bar/myfile.txt
, utilisez:Comment cela marche-t-il?
Il y a quelques composants à cela, donc je vais couvrir toute la syntaxe étape par étape.
L' utilitaire mkdir , comme spécifié dans la norme POSIX , crée des répertoires. L'
-p
argument par la documentation, fera mkdir àce qui signifie que lors de l'appel
mkdir -p /foo/bar
, mkdir créera/foo
et/foo/bar
s'il/foo
n'existe pas déjà. (Sans-p
, cela générera une erreur.L'
&&
opérateur de liste, tel que documenté dans la norme POSIX (ou le manuel Bash si vous préférez), a l'effet quicp myfile.txt $_
n'est exécuté que s'ilmkdir -p /foo/bar
s'exécute avec succès. Cela signifie que lacp
commande n'essaiera pas de s'exécuter en cas d'mkdir
échec pour l' une des nombreuses raisons pour lesquelles elle pourrait échouer .Enfin, le
$_
second argument que nous passonscp
est un "paramètre spécial" qui peut être pratique pour éviter de répéter de longs arguments (comme des chemins de fichier) sans avoir à les stocker dans une variable. Selon le manuel de Bash , il:Dans ce cas, c'est le
/foo/bar
nous sommes passés àmkdir
. Ainsi, lacp
commande se développe verscp myfile.txt /foo/bar
, qui copiemyfile.txt
dans le/foo/bar
répertoire nouvellement créé .Notez que cela ne
$_
fait pas partie de la norme POSIX , donc théoriquement une variante Unix pourrait avoir un shell qui ne prend pas en charge cette construction. Cependant, je ne connais aucun obus moderne qui ne supporte pas$_
; certainement Bash, Dash et zsh le font tous.Une dernière note: la commande que j'ai donnée au début de cette réponse suppose que vos noms de répertoires n'ont pas d'espaces. Si vous avez affaire à des noms avec des espaces, vous devrez les citer entre eux afin que les différents mots ne sont pas traités comme des arguments différents de
mkdir
oucp
. Donc, votre commande ressemblerait en fait à:la source
Une telle vieille question, mais je peux peut-être proposer une solution alternative.
Vous pouvez utiliser le
install
programme pour copier votre fichier et créer le chemin de destination "à la volée".Il y a cependant certains aspects à prendre en considération:
Vous pouvez facilement modifier le # 2 en ajoutant l'
-m
option pour définir des autorisations sur le fichier de destination (exemple:-m 664
créera le fichier de destination avec des autorisationsrw-rw-r--
, tout comme la création d'un nouveau fichier avectouch
).Et ici, c'est le lien sans vergogne vers la réponse qui m'a inspiré =)
la source
755
(rwxr-xr-x
), ce qui n'est probablement pas souhaité. vous pouvez spécifier autre chose avec le-m
commutateur, mais je n'ai pas pu trouver un moyen de simplement conserver les autorisations sur les fichiers :(Fonction Shell qui fait ce que vous voulez, en l'appelant une copie "enterrée" car elle creuse un trou dans lequel le fichier doit vivre:
la source
dirname $2
trop$2
comme argumentdirname
. Commemkdir -p "$(dirname "$2")"
. Sans cette citation$2
encp
est inutile;)dirname "$2"
&& cp -r "$ 1" "$ 2"; Notez que les backticks autourdirname $2
ne s'affichent pas car SO les analyse en tant que marqueurs de code.Voici une façon de procéder:
dirname
vous donnera le parent du répertoire ou du fichier de destination. mkdir -p `dirname ...` créera alors ce répertoire en s'assurant que lorsque vous appelez cp -r le répertoire de base correct est en place.L'avantage de ce sur-parent est qu'il fonctionne dans le cas où le dernier élément du chemin de destination est un nom de fichier.
Et cela fonctionnera sur OS X.
la source
install -D file -m 644 -t /path/to/copy/file/to/is/very/deep/there
la source
there
s'agit du fichier final et non du sous-répertoire final.avec tout mon respect pour les réponses ci-dessus, je préfère utiliser rsync comme suit:
exemple:
la source
rsync
est plus prévisible quecp
. Par exemple, si je souhaitecp /from/somedir /to-dir
alors cp se comporte différemment s'il/to-dir
existe déjà: s'il/to-dir
existe, alorscp
créera/to-dir/some-dir
, sinon juste le contenu de/from/somedir
sera placé dans/to-dir
. Cependant,rsync
se comporte de la même façon au cas où, c'est-à-dire,/to-dir/some-dir
sera toujours créé.Juste pour reprendre et donner une solution de travail complète, en une seule ligne. Soyez prudent si vous souhaitez renommer votre fichier, vous devez inclure un moyen de fournir un chemin de répertoire propre à mkdir. $ fdst peut être un fichier ou un dir. Le code suivant devrait fonctionner dans tous les cas.
ou spécifique à bash
la source
Ajoutez simplement ce qui suit dans votre .bashrc, ajustez si vous en avez besoin. Fonctionne dans Ubuntu.
Par exemple, si vous souhaitez copier le fichier "test" dans le répertoire de destination "d" Utiliser,
mkcp vérifiera d'abord si le répertoire de destination existe ou non, sinon créez-le et copiez le fichier / répertoire source.
la source
mkdir -p
. Il réussira même s'il existe déjà.Ça le fait pour moi
la source
man cp
:-R If source_file designates a directory, cp copies the directory and the entire subtree connected at that point.
J'ai écrit un script de support pour cp, appelé CP (note majuscules) qui est destiné à faire exactement cela. Le script vérifiera les erreurs dans le chemin que vous avez mis (sauf le dernier qui est la destination) et si tout va bien, il fera une étape mkdir -p pour créer le chemin de destination avant de commencer la copie. À ce stade, l'utilitaire cp normal prend le relais et tous les commutateurs que vous utilisez avec CP (comme -r, -p, -rpL sont dirigés directement vers cp). Avant d'utiliser mon script, vous devez comprendre certaines choses.
Le CP n'a pas le luxe de s'inspirer des chemins existants, il doit donc avoir des schémas de comportement très fermes. CP suppose que l'élément que vous copiez est déposé dans le chemin de destination et n'est pas la destination elle-même (c'est-à-dire une copie renommée du fichier / dossier source). Sens:
Ce comportement CP par défaut peut être modifié avec le commutateur "--rename". Dans ce cas, on suppose que
Quelques notes de clôture: Comme avec cp, CP peut copier plusieurs éléments à la fois, le dernier chemin répertorié étant supposé être la destination. Il peut également gérer des chemins avec des espaces tant que vous utilisez des guillemets.
CP vérifiera les chemins que vous avez mis et s'assurera qu'ils existent avant de faire la copie. En mode strict (disponible via l'option --strict), tous les fichiers / dossiers copiés doivent exister ou aucune copie n'a lieu. En mode détendu (--relaxed), la copie continuera si au moins un des éléments que vous avez répertoriés existe. Le mode détendu est le mode par défaut, vous pouvez changer le mode temporairement via les commutateurs ou de façon permanente en définissant la variable easy_going au début du script.
Voici comment l'installer:
Dans un terminal non root, faites:
Dans gedit, collez l'utilitaire CP et enregistrez:
la source
cp
a de multiples usages:La réponse de @ AndyRoss fonctionne pour le
style de
cp
, mais fait la mauvaise chose si vous utilisez lestyle de
cp
.Je pense que "DEST" est ambigu sans barre oblique dans cet usage (c'est-à-dire où le répertoire cible n'existe pas encore), c'est peut-être pourquoi
cp
n'a jamais ajouté une option pour cela.Voici donc ma version de cette fonction qui applique une barre oblique de fin sur le répertoire dest:
la source
Juste eu le même problème. Mon approche était de simplement tarer les fichiers dans une archive comme ceci:
tar cf your_archive.tar file1 /path/to/file2 path/to/even/deeper/file3
tar stocke automatiquement les fichiers dans la structure appropriée dans l'archive. Si vous courez
tar xf your_archive.tar
les fichiers sont extraits dans la structure de répertoires souhaitée.
la source
Comme suggéré ci-dessus par help_asap et spongeman, vous pouvez utiliser la commande 'install' pour copier des fichiers dans des répertoires existants ou créer de nouveaux répertoires de destination s'ils n'existent pas déjà.
L'option 1
install -D filename some/deep/directory/filename
copie le fichier dans un répertoire nouveau ou existant et donne les autorisations 755 par défaut au nom de fichier
Option 2
install -D filename -m640 some/deep/directory/filename
selon l'option 1 mais donne 640 autorisations de nom de fichier.
Option 3
install -D filename -m640 -t some/deep/directory/
selon l'option 2, mais cible le nom de fichier dans le répertoire cible de sorte que le nom de fichier n'a pas besoin d'être écrit à la fois dans la source et dans la cible.
Option 4
install -D filena* -m640 -t some/deep/directory/
selon l'option 3, mais utilise un caractère générique pour plusieurs fichiers.
Il fonctionne bien dans Ubuntu et combine deux étapes (création de répertoire puis copie de fichier) en une seule étape.
la source
C'est très tard, mais cela peut aider une recrue quelque part. Si vous devez créer automatiquement des dossiers, rsync devrait être votre meilleur ami. rsync / path / to / sourcefile / path / to / tragetdir / thatdoestexist /
la source
Cela pourrait fonctionner, si vous avez le bon type de
rsync
.la source
Copier de la source vers un chemin inexistant
REMARQUE: cette commande copie tous les fichiers
cp –r
pour copier tous les dossiers et son contenu$_
fonctionne comme destination qui est créée dans la dernière commandela source
Facile
devrait faire l'affaire.
la source
Disons que vous faites quelque chose comme
où A / B / C / D sont des répertoires qui n'existent pas encore
Une solution possible est la suivante
J'espère que cela pourra aider!
la source