La respuesta aceptada es incorrecta (existe una opción para cp). Ver segunda respuesta de Paul Whipp.
Ronenz
1
@Ronenz, estoy de acuerdo en que hay una opción que vale la pena mencionar en GNU cp(como respondió Paul Whipp), pero no es tan general como lo solicitó el OP. Se puede copiar a/foo/bar/filea b/foo/bar/filepero no puede copiar filea b/foo/bar/file. (es decir, solo funciona para crear directorios principales que ya existían en el caso del primer archivo, pero no puede crear directorios arbitrarios)
Sudo Bash
Parece una buena solicitud de función para cp. ¿Hay alguna posibilidad de que podamos obtener un cambio de línea de comando en un futuro cercano?
No creo que necesite el test -d: mkdir -ptodavía tiene éxito incluso si el directorio ya existe.
ephemient
Uy, cierto. Pero entonces, la prueba puede ser un bash incorporado (especialmente si está escrito como [[-d "$ d"]]) y mkdir no puede ;-)
Michael Krelin - hacker
1
mkdirestá integrado en BusyBox;)
ephemient
77
@holms, $des una variable que presumiblemente contiene el directorio en cuestión. Quiero decir, si tienes que repetirlo tres veces, es probable que primero lo asignes a la variable.
Michael Krelin - hacker
237
Si se cumple lo siguiente:
Está utilizando la versión GNU de cp(y no, por ejemplo, la versión de Mac), y
Está copiando desde alguna estructura de directorios existente y solo necesita volver a crearla
--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.
Ejemplo:
/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
Esto no funciona en Mac OS X, así que supongo que es específico de Linux.
olt
77
Yo diría que es específico de GNU. Si lo tiene macports, puede instalar coreutils y su gcp.
Michael Krelin - hacker
16
Hombre, Linux lo tiene todo
Ziggy
19
Siento que esta es la respuesta a una pregunta ligeramente diferente, a pesar de que es la respuesta que estaba buscando (y, por lo tanto, la que voté). Creo que esta es la solución si quiere enviar los directorios padre destino a ser los mismos que los directorios de origen de los padres, que es probablemente el caso de usar que la mayoría de quienes lean estas interesantes de.
David Winiecki
77
Esto supone que el directorio 'bar' ya existe, pero la pregunta original implica cómo crear automáticamente 'bar' cuando se proporciona como destino y aún no existe. La respuesta a esto es proporcionada por @ MichaelKrelin-hacker.
Thdoan
69
Respuesta corta
Para copiar myfile.txta /foo/bar/myfile.txt, use:
mkdir -p /foo/bar && cp myfile.txt $_
¿Como funciona esto?
Hay algunos componentes para esto, así que cubriré toda la sintaxis paso a paso.
Cree cualquier componente de nombre de ruta intermedio que falte
lo que significa que al llamar mkdir -p /foo/bar, mkdir creará /fooy/foo/bar si /fooaún no existe. (Sin -pembargo, en su lugar arrojará un error.
El &&operador de lista, como se documenta en el estándar POSIX (o el manual Bash si lo prefiere), tiene el efecto de que cp myfile.txt $_solo se ejecuta si se mkdir -p /foo/barejecuta con éxito. Esto significa que el cpcomando no intentará ejecutarse si mkdirfalla por una de las muchas razones por las que podría fallar .
Finalmente, $_pasamos como segundo argumento a cpun "parámetro especial" que puede ser útil para evitar repetir argumentos largos (como rutas de archivos) sin tener que almacenarlos en una variable. Según el manual de Bash :
se expande al último argumento del comando anterior
En este caso, esa es la /foo/barque pasamos mkdir. Entonces el cpcomando se expande a cp myfile.txt /foo/bar, que copia myfile.txten el /foo/bardirectorio recién creado .
Tenga en cuenta que no$_ es parte del estándar POSIX , por lo que, en teoría, una variante de Unix podría tener un shell que no sea compatible con esta construcción. Sin embargo, no conozco ningún caparazón moderno que no sea compatible ; ciertamente Bash, Dash y zsh todos lo hacen.$_
Una nota final: el comando que he dado al comienzo de esta respuesta supone que los nombres de su directorio no tienen espacios. Si está tratando con nombres con espacios, deberá citarlos para que las diferentes palabras no se tratan como argumentos diferentes para mkdiro cp. Entonces su comando realmente se vería así:
mkdir -p "/my directory/name with/spaces"&& cp "my filename with spaces.txt""$_"
Aparte: generalmente me decepciona la falta de detalles en las preguntas sobre los comandos de shell Bash o Unix en Stack Overflow, que a menudo arrojan una línea compleja y extremadamente densa que es difícil de eliminar si aún no eres un asistente de Unix. He intentado ir al extremo opuesto aquí y ambos explican cada detalle de la sintaxis y enlazan a los lugares apropiados para encontrar documentación sobre cómo funciona esto. Espero que esto ayude al menos a algunas personas. Además, el crédito es debido: descubrí este enfoque de esta respuesta a una pregunta duplicada: stackoverflow.com/a/14085147/1709587
Mark Amery
Nunca he visto $ _ antes. ¿a que se refiere? la carpeta utilizada en el último comando?
thebunnyrules
99
@thebunnyrules Pero ... pero ... hay un "¿Cómo funciona esto?" sección en mi respuesta que literalmente contiene múltiples párrafos específicamente dedicados a la pregunta que acaba de hacer. Se siente ignorado y no amado. :(
Mark Amery
Lo siento por eso. Estás absolutamente en lo correcto. Ya sabía todo lo demás en tu respuesta, así que lo escaneé rápidamente. Debería haberlo leído más cuidadosamente.
thebunnyrules
Wow, realmente pusiste mucho trabajo en esa respuesta ... Gracias por eso. Fue agradable aprender sobre: $ _. Puedo verme usándolo bastante de ahora en adelante. Escribí un script para automatizar todo el proceso y lo puse en este hilo.
Pruébalo
39
Una pregunta tan antigua, pero tal vez pueda proponer una solución alternativa.
Puede usar el installprograma para copiar su archivo y crear la ruta de destino "sobre la marcha".
Sin embargo, hay algunos aspectos a tener en cuenta:
debe especificar también el nombre del archivo de destino , no solo la ruta de destino
el archivo de destino será ejecutable (al menos, por lo que vi de mis pruebas)
Puede modificar fácilmente el # 2 agregando la -mopción de establecer permisos en el archivo de destino (ejemplo: -m 664creará el archivo de destino con permisos rw-rw-r--, al igual que crear un nuevo archivo con touch).
Realmente no funcionó para mi uso, ¡pero genial truco! Lo tendré en cuenta.
thebunnyrules
tenga en cuenta que este comando crea los archivos de destino con permisos 755( rwxr-xr-x), lo que probablemente no se desea. puede especificar algo más con el -minterruptor, pero no pude encontrar una manera de mantener los permisos del archivo :(
törzsmókus
19
Función de Shell que hace lo que quiere, llamándolo una copia "enterrada" porque cava un agujero para que el archivo viva:
@Kalmi, para una cita adecuada, también querrás citarlo $2como argumento dirname. Al igual mkdir -p "$(dirname "$2")". Sin esta cita $2en cpno sirve para nada;)
Michael Krelin - pirata informático
3
Tenga en cuenta que esta respuesta asume que $ 2 no es el directorio de destino, de lo contrario solo querría "mkdir -p" $ 2 "&& cp" $ 1 "" $ 2 "como el cuerpo de la función
usuario467257
Creo que esto tiene un error, como señala @ user467257. No creo que esto sea reparable, ya que $ 2 es ambiguo entre el directorio de destino y el archivo de destino en este escenario. He publicado una respuesta alternativa que aborda esto.
Rico
@ Rich, no estoy de acuerdo con que esto no sea reparable. Lo siguiente funciona bien tanto para archivos como para directorios: mkdir -p dirname "$2"&& cp -r "$ 1" "$ 2"; Tenga en cuenta que los backticks dirname $2no aparecen porque SO los analiza como marcadores de código.
dirnamele dará el padre del directorio o archivo de destino. mkdir -p `dirname ...` creará ese directorio asegurando que cuando llame a cp -r el directorio base correcto esté en su lugar.
La ventaja de este sobreparent es que funciona para el caso donde el último elemento en la ruta de destino es un nombre de archivo.
en realidad, no es lo mismo en absoluto. Esto requiere que pase el nombre del archivo dos veces (de ahí el indicador '-t') y establezca los bits de ejecución en el archivo (de ahí el ejemplo '-m'). la suya no debería ser la respuesta principal, ya que en realidad no responde la pregunta, mientras que la mía sí.
Spongman el
1
Esto funciona para un solo archivo. Solo tenga en cuenta que therees el archivo final y no el subdirectorio final.
kvantour
6
Con todo mi respeto por las respuestas anteriores, prefiero usar rsync de la siguiente manera:
$ rsync -a directory_name /path_where_to_inject_your_directory/
Lo intenté y obtuve este resultado: rsync -a bull / some / hoop / ti / doop / ploop RESULT rsync: mkdir "/ some / hoop / ti / doop / ploop" falló: No existe tal error de archivo o directorio (2) rsync : error en el archivo IO (código 11) en main.c (675) [Receiver = 3.1.2]
Si entiendo su sugerencia correctamente, está proponiendo que especifique una ruta completa a la fuente, alias uso: "$ (pwd) / bull" en mi comando en lugar de solo el nombre de archivo: bull? La cuestión es que el error está en que rsync crea el directorio de destino, no la fuente (bull). Me parece que rsync usa un mkdir simple y no un mkdir -p.
thebunnyrules
1
Gran utilidad, por cierto, podría comenzar a usar en mis scripts. Gracias por recomendarlo.
thebunnyrules
1
rsync Es más predecible que cp. Por ejemplo, si deseo, cp /from/somedir /to-direntonces cp se comporta de manera diferente si /to-dirya existe: si /to-direxiste, cpcreará /to-dir/some-dir, de lo contrario solo /from/somedirse colocará el contenido de /to-dir. Sin embargo, rsyncse comporta de la misma en el caso, es decir, /to-dir/some-dirserá siempre ser creado.
JoeAC
5
Solo para reanudar y dar una solución de trabajo completa, en una línea. Tenga cuidado si desea cambiar el nombre de su archivo, debe incluir una forma de proporcionar una ruta de directorio limpia a mkdir. $ fdst puede ser file o dir. El siguiente código debería funcionar en cualquier caso.
¡Gracias! Esto es lo que necesitaba. En mi caso, no sé si el destino tiene un directorio o no y si el directorio existe o no, por lo que este código me da el directorio principal que luego puedo crear de forma segura si no existe
xbmono
4
Simplemente agregue lo siguiente en su .bashrc, modifíquelo si lo necesita. Funciona en Ubuntu
mkcp(){
test -d "$2"|| mkdir -p "$2"
cp -r "$1""$2"}
Por ejemplo, si desea copiar el archivo 'prueba' al directorio de destino 'd' Use,
mkcp test a/b/c/d
mkcp primero verificará si el directorio de destino existe o no, si no, luego lo hará y copiará el archivo / directorio fuente.
De acuerdo. En man cp:-R If source_file designates a directory, cp copies the directory and the entire subtree connected at that point.
borracciaBlu
3
Escribí un script de soporte para cp, llamado CP (nota mayúsculas) que está destinado a hacer exactamente esto. El script verificará si hay errores en la ruta que ha introducido (excepto el último que es el destino) y, si todo está bien, realizará un paso mkdir -p para crear la ruta de destino antes de comenzar la copia. En este punto, la utilidad cp regular se hace cargo y cualquier interruptor que use con CP (como -r, -p, -rpL se canaliza directamente a cp). Antes de usar mi script, hay algunas cosas que debe comprender.
Se puede acceder a toda la información aquí haciendo CP --help. CP --help-all incluye los interruptores de cp.
El CP regular no realizará la copia si no encuentra la ruta de destino. No tiene una red de seguridad para errores tipográficos con CP. Se creará su destino, por lo que si escribe mal su destino como / usrr / share / icons o / usr / share / icon, eso es lo que se creará.
cp regular tiende a modelar su comportamiento en la ruta existente: cp / a / b / c / d variará dependiendo de si d existe o no. si d es una carpeta existente, cp copiará b en ella, haciendo / c / d / b. Si d no existe, b se copiará en c y se le cambiará el nombre a d. Si d existe pero es un archivo yb es un archivo, se sobrescribirá con la copia de b. Si c no existe, cp no hace la copia y sale.
CP no tiene el lujo de tomar señales de los caminos existentes, por lo que debe tener algunos patrones de comportamiento muy firmes. CP asume que el elemento que está copiando se está colocando en la ruta de destino y no es el destino en sí (también conocido como una copia renombrada del archivo / carpeta de origen). Sentido:
"CP / a / b / c / d" dará como resultado / c / d / b si d es una carpeta
"CP / a / b / c / b" dará como resultado / c / b / b si b en / c / b es una carpeta.
Si tanto byd son archivos: CP / a / b / c / d dará como resultado / c / d (donde d es una copia de b). Lo mismo para CP / a / b / c / b en la misma circunstancia.
Este comportamiento de CP predeterminado se puede cambiar con el modificador "--rename". En este caso, se supone que
"CP --rename / a / b / c / d" está copiando b en / c y renombrando la copia a d.
Algunas notas de cierre: al igual que con cp, CP puede copiar varios elementos a la vez, asumiendo que la última ruta que figura en la lista es el destino. También puede manejar rutas con espacios siempre que utilice comillas.
CP verificará las rutas que ha introducido y se asegurará de que existan antes de hacer la copia. En modo estricto (disponible mediante el interruptor --strict), todos los archivos / carpetas que se copian deben existir o no se realiza ninguna copia. En modo relajado (--relaxado), la copia continuará si existe al menos uno de los elementos enumerados. El modo relajado es el predeterminado, puede cambiar el modo temporalmente a través de los interruptores o de forma permanente configurando la variable easy_going al comienzo del script.
#!/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
Esto es quizás una exageración, pero bastante eficiente, funciona como se esperaba, gracias buen señor.
Xedret
2
cp tiene múltiples usos:
$ 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 respuesta de @ AndyRoss funciona para el
cp SOURCE DEST
estilo de cp, pero hace lo incorrecto si usa el
cp SOURCE... DIRECTORY/
estilo de cp.
Creo que "DEST" es ambiguo sin una barra inclinada final en este uso (es decir, donde el directorio de destino aún no existe), por lo que tal vez cpnunca haya agregado una opción para esto.
Así que aquí está mi versión de esta función que impone una barra inclinada final en el directorio de destino:
Como lo sugirió anteriormente help_asap y spongeman, puede usar el comando 'instalar' para copiar archivos a directorios existentes o crear crear nuevos directorios de destino si aún no existen.
La opción 1
install -D filename some/deep/directory/filename
copia el archivo en un directorio nuevo o existente y otorga permisos de nombre de archivo 755 predeterminados
Opción 2
install -D filename -m640 some/deep/directory/filename
según la Opción 1 pero otorga permisos de nombre de archivo 640.
La opción 3
install -D filename -m640 -t some/deep/directory/
según la opción 2, pero dirige el nombre del archivo al directorio de destino, por lo que el nombre del archivo no necesita escribirse tanto en el origen como en el destino.
Opción 4
install -D filena* -m640 -t some/deep/directory/
según la Opción 3 pero usa un comodín para múltiples archivos.
Funciona bien en Ubuntu y combina dos pasos (creación de directorio y copia de archivo) en un solo paso.
Esto es muy tarde, pero puede ayudar a un novato en alguna parte. Si necesita 'crear' automáticamente carpetas, rsync debería ser su mejor amigo. rsync / path / to / sourcefile / path / to / tragetdir / thatdoestexist /
cp
(como respondió Paul Whipp), pero no es tan general como lo solicitó el OP. Se puede copiara/foo/bar/file
ab/foo/bar/file
pero no puede copiarfile
ab/foo/bar/file
. (es decir, solo funciona para crear directorios principales que ya existían en el caso del primer archivo, pero no puede crear directorios arbitrarios)Respuestas:
(no hay tal opción para
cp
).fuente
test -d
:mkdir -p
todavía tiene éxito incluso si el directorio ya existe.mkdir
está integrado en BusyBox;)$d
es una variable que presumiblemente contiene el directorio en cuestión. Quiero decir, si tienes que repetirlo tres veces, es probable que primero lo asignes a la variable.Si se cumple lo siguiente:
cp
(y no, por ejemplo, la versión de Mac), yentonces puedes hacer esto con la
--parents
bandera decp
. Desde la página de información (visible en http://www.gnu.org/software/coreutils/manual/html_node/cp-invocation.html#cp-invocation o coninfo cp
oman cp
):Ejemplo:
fuente
macports
, puede instalar coreutils y sugcp
.Respuesta corta
Para copiar
myfile.txt
a/foo/bar/myfile.txt
, use:¿Como funciona esto?
Hay algunos componentes para esto, así que cubriré toda la sintaxis paso a paso.
La utilidad mkdir , como se especifica en el estándar POSIX , crea directorios. El
-p
argumento, por los documentos, hará que mkdir alo que significa que al llamar
mkdir -p /foo/bar
, mkdir creará/foo
y/foo/bar
si/foo
aún no existe. (Sin-p
embargo, en su lugar arrojará un error.El
&&
operador de lista, como se documenta en el estándar POSIX (o el manual Bash si lo prefiere), tiene el efecto de quecp myfile.txt $_
solo se ejecuta si semkdir -p /foo/bar
ejecuta con éxito. Esto significa que elcp
comando no intentará ejecutarse simkdir
falla por una de las muchas razones por las que podría fallar .Finalmente,
$_
pasamos como segundo argumento acp
un "parámetro especial" que puede ser útil para evitar repetir argumentos largos (como rutas de archivos) sin tener que almacenarlos en una variable. Según el manual de Bash :En este caso, esa es la
/foo/bar
que pasamosmkdir
. Entonces elcp
comando se expande acp myfile.txt /foo/bar
, que copiamyfile.txt
en el/foo/bar
directorio recién creado .Tenga en cuenta que no
$_
es parte del estándar POSIX , por lo que, en teoría, una variante de Unix podría tener un shell que no sea compatible con esta construcción. Sin embargo, no conozco ningún caparazón moderno que no sea compatible ; ciertamente Bash, Dash y zsh todos lo hacen.$_
Una nota final: el comando que he dado al comienzo de esta respuesta supone que los nombres de su directorio no tienen espacios. Si está tratando con nombres con espacios, deberá citarlos para que las diferentes palabras no se tratan como argumentos diferentes para
mkdir
ocp
. Entonces su comando realmente se vería así:fuente
Una pregunta tan antigua, pero tal vez pueda proponer una solución alternativa.
Puede usar el
install
programa para copiar su archivo y crear la ruta de destino "sobre la marcha".Sin embargo, hay algunos aspectos a tener en cuenta:
Puede modificar fácilmente el # 2 agregando la
-m
opción de establecer permisos en el archivo de destino (ejemplo:-m 664
creará el archivo de destino con permisosrw-rw-r--
, al igual que crear un nuevo archivo contouch
).Y aquí está el enlace descarado a la respuesta que me inspiró =)
fuente
755
(rwxr-xr-x
), lo que probablemente no se desea. puede especificar algo más con el-m
interruptor, pero no pude encontrar una manera de mantener los permisos del archivo :(Función de Shell que hace lo que quiere, llamándolo una copia "enterrada" porque cava un agujero para que el archivo viva:
fuente
dirname $2
demasiado$2
como argumentodirname
. Al igualmkdir -p "$(dirname "$2")"
. Sin esta cita$2
encp
no sirve para nada;)dirname "$2"
&& cp -r "$ 1" "$ 2"; Tenga en cuenta que los backticksdirname $2
no aparecen porque SO los analiza como marcadores de código.Aquí hay una forma de hacerlo:
dirname
le dará el padre del directorio o archivo de destino. mkdir -p `dirname ...` creará ese directorio asegurando que cuando llame a cp -r el directorio base correcto esté en su lugar.La ventaja de este sobreparent es que funciona para el caso donde el último elemento en la ruta de destino es un nombre de archivo.
Y funcionará en OS X.
fuente
install -D file -m 644 -t /path/to/copy/file/to/is/very/deep/there
fuente
there
es el archivo final y no el subdirectorio final.Con todo mi respeto por las respuestas anteriores, prefiero usar rsync de la siguiente manera:
ejemplo:
fuente
rsync
Es más predecible quecp
. Por ejemplo, si deseo,cp /from/somedir /to-dir
entonces cp se comporta de manera diferente si/to-dir
ya existe: si/to-dir
existe,cp
creará/to-dir/some-dir
, de lo contrario solo/from/somedir
se colocará el contenido de/to-dir
. Sin embargo,rsync
se comporta de la misma en el caso, es decir,/to-dir/some-dir
será siempre ser creado.Solo para reanudar y dar una solución de trabajo completa, en una línea. Tenga cuidado si desea cambiar el nombre de su archivo, debe incluir una forma de proporcionar una ruta de directorio limpia a mkdir. $ fdst puede ser file o dir. El siguiente código debería funcionar en cualquier caso.
o golpe específico
fuente
Simplemente agregue lo siguiente en su .bashrc, modifíquelo si lo necesita. Funciona en Ubuntu
Por ejemplo, si desea copiar el archivo 'prueba' al directorio de destino 'd' Use,
mkcp primero verificará si el directorio de destino existe o no, si no, luego lo hará y copiará el archivo / directorio fuente.
fuente
mkdir -p
. Tendrá éxito incluso si ya existe.Esto lo hace por mi
fuente
man cp
:-R If source_file designates a directory, cp copies the directory and the entire subtree connected at that point.
Escribí un script de soporte para cp, llamado CP (nota mayúsculas) que está destinado a hacer exactamente esto. El script verificará si hay errores en la ruta que ha introducido (excepto el último que es el destino) y, si todo está bien, realizará un paso mkdir -p para crear la ruta de destino antes de comenzar la copia. En este punto, la utilidad cp regular se hace cargo y cualquier interruptor que use con CP (como -r, -p, -rpL se canaliza directamente a cp). Antes de usar mi script, hay algunas cosas que debe comprender.
CP no tiene el lujo de tomar señales de los caminos existentes, por lo que debe tener algunos patrones de comportamiento muy firmes. CP asume que el elemento que está copiando se está colocando en la ruta de destino y no es el destino en sí (también conocido como una copia renombrada del archivo / carpeta de origen). Sentido:
Este comportamiento de CP predeterminado se puede cambiar con el modificador "--rename". En este caso, se supone que
Algunas notas de cierre: al igual que con cp, CP puede copiar varios elementos a la vez, asumiendo que la última ruta que figura en la lista es el destino. También puede manejar rutas con espacios siempre que utilice comillas.
CP verificará las rutas que ha introducido y se asegurará de que existan antes de hacer la copia. En modo estricto (disponible mediante el interruptor --strict), todos los archivos / carpetas que se copian deben existir o no se realiza ninguna copia. En modo relajado (--relaxado), la copia continuará si existe al menos uno de los elementos enumerados. El modo relajado es el predeterminado, puede cambiar el modo temporalmente a través de los interruptores o de forma permanente configurando la variable easy_going al comienzo del script.
Aquí se explica cómo instalarlo:
En un terminal no root, haga:
En gedit, pegue la utilidad CP y guarde:
fuente
cp
tiene múltiples usos:La respuesta de @ AndyRoss funciona para el
estilo de
cp
, pero hace lo incorrecto si usa elestilo de
cp
.Creo que "DEST" es ambiguo sin una barra inclinada final en este uso (es decir, donde el directorio de destino aún no existe), por lo que tal vez
cp
nunca haya agregado una opción para esto.Así que aquí está mi versión de esta función que impone una barra inclinada final en el directorio de destino:
fuente
Solo tuve el mismo problema. Mi enfoque era simplemente colocar los archivos en un archivo así:
tar cf your_archive.tar file1 /path/to/file2 path/to/even/deeper/file3
tar almacena automáticamente los archivos en la estructura adecuada dentro del archivo. Si tu corres
tar xf your_archive.tar
los archivos se extraen en la estructura de directorios deseada.
fuente
Como lo sugirió anteriormente help_asap y spongeman, puede usar el comando 'instalar' para copiar archivos a directorios existentes o crear crear nuevos directorios de destino si aún no existen.
La opción 1
install -D filename some/deep/directory/filename
copia el archivo en un directorio nuevo o existente y otorga permisos de nombre de archivo 755 predeterminados
Opción 2
install -D filename -m640 some/deep/directory/filename
según la Opción 1 pero otorga permisos de nombre de archivo 640.
La opción 3
install -D filename -m640 -t some/deep/directory/
según la opción 2, pero dirige el nombre del archivo al directorio de destino, por lo que el nombre del archivo no necesita escribirse tanto en el origen como en el destino.
Opción 4
install -D filena* -m640 -t some/deep/directory/
según la Opción 3 pero usa un comodín para múltiples archivos.
Funciona bien en Ubuntu y combina dos pasos (creación de directorio y copia de archivo) en un solo paso.
fuente
Esto es muy tarde, pero puede ayudar a un novato en alguna parte. Si necesita 'crear' automáticamente carpetas, rsync debería ser su mejor amigo. rsync / path / to / sourcefile / path / to / tragetdir / thatdoestexist /
fuente
Esto podría funcionar, si tiene el tipo correcto de
rsync
.fuente
Copiar desde el origen a una ruta no existente
NOTA: este comando copia todos los archivos
cp –r
para copiar todas las carpetas y su contenido$_
trabajar como destino que se crea en el último comandofuente
Simple
debería hacer el truco.
fuente
Digamos que estás haciendo algo como
donde A / B / C / D son directorios que aún no existen
Una posible solución es la siguiente
¡Espero que ayude!
fuente