如何在R中复制带符号链接的文件夹/目录?

时间:2022-04-01 16:26:33

I have an R function that uses a directory with relative symbolic links (e.g. ../../data) as a template. I know the relative links will be valid since the function puts the template in a specific part of a known file structure. The file.copy function can copy directories with recrusive = TRUE, but it turns the symbolic links into copies of the directories they point to. The linux system command cp -r path1 path2 will copy the links correctly, but I want to use R functions when possible.

我有一个R函数,它使用一个带有相对符号链接的目录(例如../../data)作为模板。我知道相对链接是有效的,因为函数将模板放在已知文件结构的特定部分。 file.copy函数可以使用recrusive = TRUE复制目录,但它会将符号链接转换为它们指向的目录的副本。 linux系统命令cp -r path1 path2将正确复制链接,但我希望尽可能使用R函数。

How do I copy a directory in R that contains relative symbolic links that point outside the directory?

如何复制R中包含指向目录外部的相对符号链接的目录?

I know I could write my own function that recursivly lists files (list.dirs), finds symbolic links (Sys.readlink), and recreates them (file.link), while copying all other files, but I wanted to know if that functionality already exists.

我知道我可以编写自己的函数,递归列出文件(list.dirs),找到符号链接(Sys.readlink),并重新创建它们(file.link),同时复制所有其他文件,但我想知道是否有这个功能已经存在。

1 个解决方案

#1


I have come up with a solution, so I figured I would post it in case others might need to do this and there is actually not a more conventional way to do it. I am still interested in hearing other answers!

我想出了一个解决方案,所以我想我会发布它,以防其他人可能需要这样做,实际上没有更传统的方法来做到这一点。我仍然有兴趣听到其他答案!

I came up with the following function:

我想出了以下功能:

#===================================================================================================
#' Copy folders with links
#' 
#' Copies folders like \link{\code{file.copy}} except it replicates links correctly on unix-like 
#' systems.
#' 
#' @param from (\code{character}) The path to the folder to be copied
#' @param to (\code{character}) Where to copy the folder to. 
#' 
copy_folder_with_links <- function(from, to) {
  target <- file.path(to, basename(from))
  if (file.exists(target)) stop(paste0("Target folder ", target, " already exists."))
  # Get list of all files/folders to copy ----------------------------------------------------------
  path <- data.frame(target = list.files(from, recursive = TRUE, all.files = TRUE, include.dirs = TRUE))
  path$from  <- file.path(from, path$target)
  path$to  <- file.path(to, basename(from), path$target)
  # Get type of file/folders -----------------------------------------------------------------------
  path$type <- factor("file", levels = c("file", "folder", "link"))
  path$type[file.info(path$from)$isdir] <- "folder"
  path$type[Sys.readlink(path$from) != ""] <- "link"
  # Remove all files that are descendants of links -------------------------------------------------
  is_child <- function(query, refs) {
    sapply(refs, function(x) grepl(paste0("^", x), query) & query != x)
  }
  path <- path[!sapply(path$from, function(x) any(is_child(x, path$from) & path$type == "link")), ]
  # Make copy --------------------------------------------------------------------------------------
  invisible(lapply(path$to[path$type == "folder"], dir.create, recursive = TRUE))
  invisible(file.copy(from = path$from[path$type == "file"], to = path$to[path$type == "file"]))
  invisible(file.symlink(Sys.readlink(path$from[path$type == "link"]), path$to[path$type == "link"]))
}

It works like file.copy (with less options), but correctly copies links. It works by

它的工作方式类似于file.copy(选项较少),但可以正确复制链接。它的工作原理

  1. Getting a list of all files/folders to be copied using list.files(from, recursive = TRUE, all.files = TRUE, include.dirs = TRUE)
  2. 使用list.files获取要复制的所有文件/文件夹的列表(from,recursive = TRUE,all.files = TRUE,include.dirs = TRUE)

  3. Determining whether each is a file, folder, or link
  4. 确定每个文件是文件,文件夹还是链接

  5. Removing descendants of linked folders from the list (since links are followed by list.files)
  6. 从列表中删除链接文件夹的后代(因为链接后面是list.files)

  7. Copying the folders, files, and links (in that order)
  8. 复制文件夹,文件和链接(按此顺序)

#1


I have come up with a solution, so I figured I would post it in case others might need to do this and there is actually not a more conventional way to do it. I am still interested in hearing other answers!

我想出了一个解决方案,所以我想我会发布它,以防其他人可能需要这样做,实际上没有更传统的方法来做到这一点。我仍然有兴趣听到其他答案!

I came up with the following function:

我想出了以下功能:

#===================================================================================================
#' Copy folders with links
#' 
#' Copies folders like \link{\code{file.copy}} except it replicates links correctly on unix-like 
#' systems.
#' 
#' @param from (\code{character}) The path to the folder to be copied
#' @param to (\code{character}) Where to copy the folder to. 
#' 
copy_folder_with_links <- function(from, to) {
  target <- file.path(to, basename(from))
  if (file.exists(target)) stop(paste0("Target folder ", target, " already exists."))
  # Get list of all files/folders to copy ----------------------------------------------------------
  path <- data.frame(target = list.files(from, recursive = TRUE, all.files = TRUE, include.dirs = TRUE))
  path$from  <- file.path(from, path$target)
  path$to  <- file.path(to, basename(from), path$target)
  # Get type of file/folders -----------------------------------------------------------------------
  path$type <- factor("file", levels = c("file", "folder", "link"))
  path$type[file.info(path$from)$isdir] <- "folder"
  path$type[Sys.readlink(path$from) != ""] <- "link"
  # Remove all files that are descendants of links -------------------------------------------------
  is_child <- function(query, refs) {
    sapply(refs, function(x) grepl(paste0("^", x), query) & query != x)
  }
  path <- path[!sapply(path$from, function(x) any(is_child(x, path$from) & path$type == "link")), ]
  # Make copy --------------------------------------------------------------------------------------
  invisible(lapply(path$to[path$type == "folder"], dir.create, recursive = TRUE))
  invisible(file.copy(from = path$from[path$type == "file"], to = path$to[path$type == "file"]))
  invisible(file.symlink(Sys.readlink(path$from[path$type == "link"]), path$to[path$type == "link"]))
}

It works like file.copy (with less options), but correctly copies links. It works by

它的工作方式类似于file.copy(选项较少),但可以正确复制链接。它的工作原理

  1. Getting a list of all files/folders to be copied using list.files(from, recursive = TRUE, all.files = TRUE, include.dirs = TRUE)
  2. 使用list.files获取要复制的所有文件/文件夹的列表(from,recursive = TRUE,all.files = TRUE,include.dirs = TRUE)

  3. Determining whether each is a file, folder, or link
  4. 确定每个文件是文件,文件夹还是链接

  5. Removing descendants of linked folders from the list (since links are followed by list.files)
  6. 从列表中删除链接文件夹的后代(因为链接后面是list.files)

  7. Copying the folders, files, and links (in that order)
  8. 复制文件夹,文件和链接(按此顺序)