Comando cp: copiar correctamente carpetas de archivos en *nix
Este artículo revelará algunas cosas no obvias relacionadas con el uso de comodines al copiar, comportamiento de comando ambiguo cp al copiar, así como métodos que le permiten copiar correctamente una gran cantidad de archivos sin saltarlos ni bloquearlos.
Digamos que necesitamos copiar todo desde la carpeta/fuente a la carpeta/destino.
Lo primero que me viene a la mente es:
cp /source/* /target
Corrijamos inmediatamente este comando para:
cp -a /source/* /target
Llave -a agregará la copia de todos los atributos, derechos y agregará recursividad. Cuando no se requiere la reproducción exacta de los derechos, una clave es suficiente -r.
Después de copiar, encontraremos que no se copiaron todos los archivos: archivos que comienzan con un punto como:
.profile
.local
.mc
y similares.
¿Por qué sucedió esto?
Debido a que los comodines son procesados por el shell (bash en un caso típico). De forma predeterminada, bash ignorará todos los archivos que comiencen con puntos, ya que los trata como ocultos. Para evitar este comportamiento tendremos que cambiar el comportamiento. bash usando el comando:
shopt -s dotglob
Para garantizar que este cambio de comportamiento persista después de reiniciar, puede crear un archivo comodín.sh con este comando en la carpeta /etc/profile.d (Quizás tu distribución tenga una carpeta diferente).
Y si no hay archivos en el directorio de origen, entonces el shell no podrá sustituir nada en lugar del asterisco y la copia también fallará con un error. Hay opciones frente a esta situación failglob и nullglob. Necesitaremos establecer failglob, lo que impedirá que se ejecute el comando. nullglob no funcionará, ya que convierte una cadena con comodines que no encontró una coincidencia en una cadena vacía (longitud cero), que por cp provocará un error.
Sin embargo, si hay miles de archivos o más en la carpeta, entonces se debe abandonar por completo el método de los comodines. El hecho es que bash expande los comodines en una línea de comando muy larga como:
cp -a /souce/a /source/b /source/c …… /target
Hay un límite en la longitud de la línea de comando, que podemos averiguar usando el comando:
getconf ARG_MAX
Obtengamos la longitud máxima de la línea de comando en bytes:
2097152
Или:
xargs --show-limits
Obtenemos algo como:
….
Maximum length of command we could actually use: 2089314
….
Entonces, prescindamos por completo de los comodines.
solo escribamos
cp -a /source /target
Y aquí nos enfrentamos a una ambigüedad de comportamiento. cp. Si la carpeta /target no existe, obtendremos lo que necesitamos.
Sin embargo, si la carpeta de destino existe, los archivos se copiarán a la carpeta /destino/fuente.
No siempre podemos eliminar la carpeta /target por adelantado, ya que puede contener archivos que necesitamos y nuestro objetivo, por ejemplo, es complementar los archivos en /target con archivos de /source.
Si las carpetas de origen y de destino tuvieran el mismo nombre, por ejemplo, estuviéramos copiando de /fuente a /home/fuente, entonces podríamos usar el comando:
cp -a /source /home
Y después de copiar, los archivos en /home/source se complementarían con archivos de /source.
Este es un problema lógico: podemos agregar archivos en el directorio de destino si las carpetas tienen el mismo nombre, pero si son diferentes, entonces la carpeta de origen se colocará dentro del destino. ¿Cómo copiar archivos de/fuente a/destino usando cp sin comodines?
Para sortear esta dañina limitación, utilizamos una solución no obvia:
cp -a /source/. /target
Quienes estén familiarizados con DOS y Linux ya lo han entendido todo: dentro de cada carpeta hay 2 carpetas invisibles “.” y “..”, que son enlaces de pseudocarpetas a los directorios actuales y superiores.
Al copiar cp comprueba la existencia e intenta crear /target/.
Dicho directorio existe y es /target
Los archivos de /source se copian a /target correctamente.
Así que cuélgalo en un marco llamativo en tu memoria o en la pared:
cp -a /source/. /target
El comportamiento de este comando es claro. Todo funcionará sin errores, sin importar si tienes un millón de archivos o ninguno.
Hallazgos
Si necesitas copiar todos archivos de una carpeta a otra, no usamos comodines, es mejor usarlos en su lugar cp combinado con un punto al final de la carpeta de origen. Esto copiará todos los archivos, incluidos los ocultos, y no fallará con millones de archivos o ningún archivo.
Epílogo
vmspike sugirió una versión de comando con un resultado similar: