varios todos subdirectorios renombrar recursiva otro mover los listar ejemplos directorios directorio crear copiar copia comandos basicos archivos archivo linux bash shell unix cp

todos - mover varios archivos en linux



Linux: copia y crea el directorio de destino si no existe (16)

Respuesta corta

Para copiar myfile.txt a /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.

La utilidad mkdir , como se especifica en el estándar POSIX , crea directorios. El argumento -p , según los documentos, hará que mkdir

Cree cualquier componente intermedio faltante de la ruta

lo que significa que al llamar a mkdir -p /foo/bar , mkdir creará /foo y /foo/bar si /foo aún no existe. (Sin -p , en su lugar lanzará un error.

El operador de la lista && , como se documenta en el estándar POSIX (o el manual de Bash si lo prefiere), tiene el efecto de que cp myfile.txt $_ solo se ejecuta si mkdir -p /foo/bar ejecuta correctamente. Esto significa que el comando cp no intentará ejecutarse si mkdir falla por una de las muchas razones por las que podría fallar .

Finalmente, el $_ que aprobamos como segundo argumento de cp es un "parámetro especial" que puede ser útil para evitar repetir argumentos largos (como rutas de archivos) sin tener que almacenarlos en una variable. Por el manual de Bash , que:

Se expande hasta el último argumento del comando anterior.

En este caso, ese es el /foo/bar que pasamos a mkdir . Entonces, el comando cp expande a cp myfile.txt /foo/bar , que copia myfile.txt en el directorio /foo/bar recién creado.

Tenga en cuenta que $_ no es parte del estándar POSIX , por lo que teóricamente una variante de Unix podría tener un shell que no admita esta construcción. Sin embargo, no conozco ninguna concha moderna que no admita $_ ; Ciertamente Bash, Dash, y zsh todos lo hacen.

Una nota final: el comando que he dado al comienzo de esta respuesta asume que los nombres de su directorio no tienen espacios. Si está tratando con nombres con espacios, deberá citarlos para que las diferentes palabras no son tratados como argumentos diferentes a mkdir o cp . Entonces tu orden se vería como:

mkdir -p "/my directory/name with/spaces" && cp "my filename with spaces.txt" "$_"

Quiero un comando (o probablemente una opción para cp) que cree el directorio de destino si no existe.

Ejemplo:

cp -? file /path/to/copy/file/to/is/very/deep/there


Aquí hay una forma de hacerlo:

mkdir -p `dirname /path/to/copy/file/to/is/very/deep/there` / && cp -r file /path/to/copy/file/to/is/very/deep/there

dirname le dará el padre del directorio o archivo de destino. mkdir -p `dirname ...` creará ese directorio asegurándose de que cuando llame a cp -r esté en su lugar el directorio base correcto.

La ventaja de esto sobre los padres es que funciona en el caso de que el último elemento en la ruta de destino sea un nombre de archivo.

Y funcionará en OS X.


Con todo mi respeto por las respuestas anteriores, prefiero usar rsync como sigue:

$ rsync -a directory_name /path_where_to_inject_your_directory/

ejemplo:

$ rsync -a test /usr/local/lib/


Copiar desde la fuente a una ruta no existente

mkdir –p /destination && cp –r /source/ $_

NOTA: este comando copia todos los archivos

cp –r para copiar todas las carpetas y su contenido

$_ trabajo como destino que se crea en el último comando


Digamos que estas haciendo algo como

cp file1.txt A / B / C / D / file.txt

donde A / B / C / D son directorios que aún no existen

Una posible solución es la siguiente

DIR=$(dirname A/B/C/D/file.txt) # DIR= "A/B/C/D" mkdir -p $DIR cp file1.txt A/B/C/D/file.txt

¡Espero que ayude!


Escribí un script de soporte para cp, llamado CP (nota mayúscula) que pretende hacer exactamente esto. La secuencia de comandos buscará errores en la ruta que has introducido (excepto la última que es el destino) y si todo está bien, hará un paso mkdir -p para crear la ruta de destino antes de iniciar la copia. En este punto, la utilidad cp normal asume el control y cualquier conmutador que use con CP (como -r, -p, -rpL se canaliza directamente a cp). Antes de usar mi script, hay algunas cosas que debes entender.

  • Se puede acceder a toda la información aquí haciendo CP - help. CP --help-all incluye los conmutadores de cp.
  • cp normal no hará la copia si no encuentra la ruta de destino. Usted no tiene una red de seguridad para los errores tipográficos con CP. Se creará su destino, por lo que si escribe incorrectamente su destino como / usrr / share / icons o / usr / share / icon, eso es lo que se va a crear.
  • cp normal tiende a modelar su comportamiento en la ruta existente: cp / a / b / c / d variará 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 cambiará a d. Si d existe pero es un archivo y b es un archivo, se sobrescribirá con la copia de b. Si c no existe, cp no hace la copia y sale.

CP no puede darse el lujo de seguir las 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á cayendo en la ruta de destino y no es el destino en sí mismo (también conocido como una copia renombrada del archivo / carpeta de origen). Sentido:

  • "CP / a / b / c / d" resultará en / c / d / b si d es una carpeta
  • "CP / a / b / c / b" resultará en / c / b / b si b en / c / b es una carpeta.
  • Si tanto b como d son archivos: CP / a / b / c / d resultará en / 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 interruptor "--rename". En este caso, se supone que

  • "CP --rename / a / b / c / d" está copiando b en / c y cambiando el nombre de la copia a d.

Algunas notas de cierre: al igual que con cp, CP puede copiar varios elementos a la vez, y se supone que el último camino aparece como destino. También puede manejar rutas con espacios siempre que use comillas.

CP verificará las rutas que has introducido y se asegurará de que existan antes de hacer la copia. En modo estricto (disponible a través de --strict switch), todos los archivos / carpetas que se están copiando deben existir o no se realizará ninguna copia. En el modo relajado (--lactado), la copia continuará si al menos uno de los elementos enumerados existe. El modo relajado es el predeterminado, puede cambiar el modo temporalmente a través de los interruptores o permanentemente configurando la variable easy_going al principio del script.

Aquí está cómo instalarlo:

En un terminal no root, haga:

sudo echo > /usr/bin/CP; sudo chmod +x /usr/bin/CP; sudo touch /usr/bin/CP gedit admin:///usr/bin/CP

En gedit, pega la utilidad CP y guarda:

#!/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 needed while true; do eval input="/$$n" in_=${input::1} if [ -z "$input" -a $n = 1 ]; then input="--help"; fi if [ "$input" = "-h" -o "$input" = "--help" -o "$input" = "-?" -o "$input" = "--help-all" ]; then if [ "$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 fi if [ -z "$input" ]; then count_i=$(expr $count_i - 1 ) # remember, last item is destination and it''s not included in cound break elif [ "$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 destination if [ $count_i -lt 0 ]; then echo "Error: You haven''t listed any items for copying. Exiting." # you didn''t put any items for copying elif [ $count_i -lt 1 ]; then echo "Error: Copying usually involves a destination. Exiting." # you put one item and no destination fi #reset the counter and grab content of arguments, aka: switches and item paths n=1 while true; do eval input="/$$n" #input=$1,$2,$3,etc... in_=${input::1} #first letter of $input if [ "$in_" = "-" ]; then if [ "$input" = "--rename" ]; then rename=true #my custom switches elif [ "$input" = "--strict" ]; then easy_going=false #exit script if even one of the non-destinations item is not found elif [ "$input" = "--relaxed" ]; then easy_going=true #continue script if at least one of the non-destination items is found elif [ "$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/"" fi elif ! [ -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/"" else if [ "$i" -le "$count_i" ]; then eval item$i="$input" item_list="$item_list /"$input/"" else destination="$input" #destination is last items entered fi fi else i=0 m=0 n=1 break fi 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 fi if [ $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" ]; then if [ $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 fi fi if [ "$rename" = true ]; then if [ $count_i -gt 1 ]; then if [ $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 fi elif [ -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 fi else dest_jr=$(dirname "$destination") if [ -d "$destination" ]; then item_list="$item1/*";fi mkdir -p "$dest_jr" fi else mkdir -p "$destination" fi eval 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 lo hace por mi

cp -vaR ./from ./to


Función de shell que hace lo que usted quiere, llamándola copia "enterrada" porque cava un agujero para que el archivo viva:

bury_copy() { mkdir -p `dirname $2` && cp "$1" "$2"; }


Si ambas de las siguientes son verdaderas:

  1. Está utilizando la versión de GNU de cp (y no, por ejemplo, la versión de Mac), y
  2. Está copiando desde alguna estructura de directorios existente y solo necesita volver a crearlo

entonces puedes hacer esto con la bandera de --parents de cp . Desde la página de información (visible en http://www.gnu.org/software/coreutils/manual/html_node/cp-invocation.html#cp-invocation o con info cp o man cp ):

--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


Simplemente agrega lo siguiente en tu .bashrc, modifica si es necesario. Funciona en Ubuntu.

mkcp() { test -d "$2" || mkdir -p "$2" cp -r "$1" "$2" }

Por ejemplo, si desea copiar el archivo de ''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, entonces lo hará y copiará el archivo / directorio de origen.


Solo para reanudar y dar una solución completa de trabajo, en una sola línea. Tenga cuidado si desea cambiar el nombre de su archivo, debe incluir una forma de proporcionar una ruta de acceso de directorio limpia a mkdir. $ fdst puede ser file o dir. El siguiente código debería funcionar en cualquier caso.

fsrc=/tmp/myfile.unk fdst=/tmp/dir1/dir2/dir3/myfile.txt mkdir -p $(dirname ${fdst}) && cp -p ${fsrc} ${fdst}

o bash específico

fsrc=/tmp/myfile.unk fdst=/tmp/dir1/dir2/dir3/myfile.txt mkdir -p ${fdst%/*} && cp -p ${fsrc} ${fdst}


Una pregunta tan antigua, pero tal vez pueda proponer una solución alternativa.

Puede usar el programa de install para copiar su archivo y crear la ruta de destino "sobre la marcha".

install -D file /path/to/copy/file/to/is/very/deep/there/file

Hay algunos aspectos a tener en cuenta, sin embargo:

  1. También debe especificar el nombre del archivo de destino , no solo la ruta de destino
  2. el archivo de destino será ejecutable (al menos, por lo que vi en mis pruebas)

Puede modificar fácilmente el # 2 agregando la opción -m para establecer permisos en el archivo de destino (ejemplo: -m 664 creará el archivo de destino con los permisos rw-rw-r-- , al igual que crear un nuevo archivo con touch ) .

Y aquí está el enlace descarado a la respuesta que me inspiró =)


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 Andy Andy 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 diagonal en este uso (es decir, donde el directorio de destino aún no existe), tal vez por eso cp nunca ha agregado una opción para esto.

Así que aquí está mi versión de esta función que impone una barra diagonal final en el directorio de destino:

cp-p() { last=${@: -1} if [[ $# -ge 2 && "$last" == */ ]] ; then # cp SOURCE... DEST/ mkdir -p "$last" && cp "$@" else echo "cp-p: (copy, creating parent dirs)" echo "cp-p: Usage: cp-p SOURCE... DEST/" fi }


install -D file -m 644 -t /path/to/copy/file/to/is/very/deep/there


mkdir -p "$d" && cp file "$d"

(no hay tal opción para cp ).


rsync file /path/to/copy/file/to/is/very/deep/there

Esto podría funcionar, si tiene el tipo correcto de rsync .