¿Cómo forzar a 'cp' a sobrescribir el directorio en lugar de crear otro dentro?

107

Estoy tratando de escribir un script Bash que sobrescriba un directorio existente. Tengo un directorio foo/y estoy tratando de sobrescribirlo bar/. Pero cuando hago esto:

cp -Rf foo/ bar/

bar/foo/se crea un nuevo directorio. No quiero eso. Hay dos archivos en foo/; ay b. También hay archivos con los mismos nombres bar/. Quiero que foo/ay foo/breemplace bar/ay bar/b.

saketrp
fuente

Respuestas:

122

Puede hacer esto usando la -Topción en cp.
Consulte la página Man para cp.

-T, --no-target-directory
    treat DEST as a normal file

Entonces, según su ejemplo, la siguiente es la estructura del archivo.

$ tree test
test
|-- bar
|   |-- a
|   `-- b
`-- foo
    |-- a
    `-- b
2 directories, 4 files

Puede ver la clara diferencia cuando lo usa -vpara Verbose.
Cuando usa solo -Roption.

$ cp -Rv foo/ bar/
`foo/' -> `bar/foo'
`foo/b' -> `bar/foo/b'
`foo/a' -> `bar/foo/a'
 $ tree
 |-- bar
 |   |-- a
 |   |-- b
 |   `-- foo
 |       |-- a
 |       `-- b
 `-- foo
     |-- a
     `-- b
3 directories, 6 files

Cuando usa la opción -T, sobrescribe el contenido, tratando el destino como un archivo normal y no como un directorio .

$ cp -TRv foo/ bar/
`foo/b' -> `bar/b'
`foo/a' -> `bar/a'

$ tree
|-- bar
|   |-- a
|   `-- b
`-- foo
    |-- a
    `-- b
2 directories, 4 files

Esto debería solucionar tu problema.

Saurabh Meshram
fuente
22
en caso de que alguien se tropiece con esto, no funcionará con OSX cp developer.apple.com/library/mac/documentation/Darwin/Reference/…
dnfehren
9
No está claro que esta respuesta sea lo que está buscando el OP, aunque los ejemplos dados anteriormente enmascaran el problema ... Con la opción -T, los archivos que están en un destino existente ( bar/) pero no en la fuente ( foo/) se dejarán en su lugar, por lo que esto no es lo que la mayoría de la gente consideraría una sobrescritura completa del directorio. es decir. si bar/bazya existiera, seguiría existiendo después ...
robo
1
Esta respuesta responde a la pregunta op, pero no aborda el caso de si el destino ya existe y desea eliminar el contenido que contiene, pero el directorio de origen no. Este no es un comportamiento esperado de copiar archivos de un lugar a otro. Solo sobrescribe las cosas de destino que también están en la fuente, no toca nada en el destino que no esté en la fuente. Puede limpiar la carpeta de destino anteponiendo un comando para hacerlo:rm -rf bar/* && cp -TRv foo/ bar/
theferrit32
1
No soy un lector de la mente ... No veo más aclaraciones lo que el PO estaba buscando, pero esto es sin duda la respuesta que yo (MEEEE) estaba buscando
Assimilater
2
en caso de que alguien se tropiece con el motivo por el que el enlace del comentario más votado no funciona, aquí está: web.archive.org/web/20170909193852/https://developer.apple.com/…
Sulphur
48

Hágalo en dos pasos.

rm -r bar/
cp -r foo/ bar/
Jonathan Wheeler
fuente
11
En realidad, este es el único ejemplo dado hasta ahora que asegurará que el barcontenido sea idéntico foo, no una combinación de elementos de foomás otros elementos que ya existían bar. La respuesta altamente votada de @Saurabh Meshram a continuación tiene este problema.
robo
1
Tenga mucho cuidado con esto, ya que va a eliminar todos los archivos de la barra, incluso los ocultos.
Elia Grady
mac osx: rm -rf bar/; cp -r foo/ !$
Michael Dimmitt
1
Esto no siempre es viable ... o deseado ... imagina si fooy barson directorios grandes ... tal vez hay archivos barque no están y fooque no quieres eliminar. Esto no debería considerarse una respuesta realista en mi humilde opinión
Assimilater
Aunque funcionó para mí, pero no es la mejor solución, ya que puede haber un archivo incluido en foo / pero no en bar / que se eliminará después de hacer esto.
Nitwit
46

Si desea asegurarse de que bar/termine siendo idéntico a foo/, use rsyncen su lugar:

rsync -a --delete foo/ bar/

Si solo han cambiado algunas cosas, esto se ejecutará mucho más rápido que eliminar y volver a copiar todo el directorio.

  • -aes 'modo de archivo', que copia los archivos fielmente en foo/abar/
  • --deleteelimina archivos adicionales no en foo/partir bar/, así, asegurarbar/ termina idénticos
  • Si quiere ver lo que está haciendo, agregue -vh para verboso y legible para humanos
  • Nota: foose requiere la barra inclinada posterior ; de lo contrario, rsyncse copiará foo/en bar/foo/lugar de sobrescribirbar/ .
    • (Las barras inclinadas después de los directorios en rsync son confusas; si está interesado, aquí está la primicia. Le dicen a rsync que se refiera al contenido del directorio, en lugar del directorio en . Por lo tanto, para sobrescribir el contenido de foo/sobre el contenido de bar/, use una barra en ambos. Es confuso porque no funcionará como se espera con una barra en ninguno , sin embargo; rsync siempre interpreta furtivamente la ruta de destino como si tuviera una barra, a pesar de que respeta la ausencia de una barra en el origen ruta. Por lo tanto, necesitamos una barra en la ruta de origen para que coincida con la barra que se agrega automáticamente en la ruta de destino, si queremos copiar el contenido de foo/en bar/, en lugar del directoriofoo/aterrizando en bar/como bar/foo.)

rsync es muy poderoso y útil, si tiene curiosidad, busque qué más puede hacer (como copiar sobre ssh).

Tom Potter
fuente
1
Me gusta esta respuesta mejor que la cp -Topción porque también funciona en macosx 👍
tongueroo
18

Utilice este cpcomando:

cp -Rf foo/* bar/
anubhava
fuente
9
Esto no elimina los archivos que están presentes en bar pero no en foo.
Ara
5
No sé a qué te refieres con eso. ¿Por qué debería el cpcomando eliminar el archivo de la fuente?
anubhava
Tengo entendido que cuando 'sobrescribe un directorio existente' con otro, al final, el directorio sobrescrito debería ser una copia del otro. Es decir, en la barra final debería haber una copia de foo, como es el caso de la respuesta de @ jonathan-wheeler, pero si tenía un archivo bar / cy no foo / c, entonces bar / c no se elimina. En una nota al margen, acabo de notar que tampoco es el caso con la respuesta de Saurabh Meshram.
Ara
Tal vez no estemos de acuerdo en lo que significa sobrescribir, para mí es básicamente reemplazar, mientras que usted podría querer decir megre. Es difícil decir qué quiere OP exactamente porque solo mencionó 2 archivos que están en foo y bar.
Ara
Esta sintaxis también ignora los archivos de puntos ocultos. Un gran número también puede hacer estallar el globo.
xpusostomos
13

El siguiente comando asegura que los archivos dotfiles (archivos ocultos) estén incluidos en la copia:

$ cp -Rf foo/. bar
Mayo Oakes
fuente
1
¿Es esto cierto? Parece inusual.
Mateng
2
@Mateng Acabo de probarlo, sí, es cierto.
Matmarbon
1
.significa todos los archivos en el directorio. Entonces, naturalmente, se incluirían los archivos ocultos.
Jaspreet Singh
Eso es bastante bueno en realidad. También puede hacer "cp -RTf foo bar" en Linux.
xpusostomos
5

Muy similar a @Jonathan Wheeler:

Si no quiere recordar, pero no reescribir bar:

rm -r bar/
cp -r foo/ !$

!$ muestra el último argumento de su comando anterior.

Michael Dimmitt
fuente
4
¡El consejo sobre! $ Es increíble!
Lucas Morgan
0

Esto debería solucionar tu problema.

\cp -rf foo/* bar/
Ali
fuente
-1

La operación que definió es una "combinación" y no puede hacer eso con cp. Sin embargo, si no está buscando fusionar y está bien perder la carpeta bar, simplemente puede rm -rf bareliminar la carpeta y luego mv foo barcambiarle el nombre. Esto no llevará ningún tiempo, ya que ambas operaciones se realizan mediante punteros de archivo, no con el contenido del archivo.

Ati
fuente
-2

Intente utilizar este comando compuesto por dos pasos:

rm -rf bar && cp -r foo bar
Yahor M
fuente