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(选项较少),但可以正确复制链接。它的工作原理
- Getting a list of all files/folders to be copied using
list.files(from, recursive = TRUE, all.files = TRUE, include.dirs = TRUE)
- Determining whether each is a file, folder, or link
- Removing descendants of linked folders from the list (since links are followed by
list.files
) - Copying the folders, files, and links (in that order)
使用list.files获取要复制的所有文件/文件夹的列表(from,recursive = TRUE,all.files = TRUE,include.dirs = TRUE)
确定每个文件是文件,文件夹还是链接
从列表中删除链接文件夹的后代(因为链接后面是list.files)
复制文件夹,文件和链接(按此顺序)
#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(选项较少),但可以正确复制链接。它的工作原理
- Getting a list of all files/folders to be copied using
list.files(from, recursive = TRUE, all.files = TRUE, include.dirs = TRUE)
- Determining whether each is a file, folder, or link
- Removing descendants of linked folders from the list (since links are followed by
list.files
) - Copying the folders, files, and links (in that order)
使用list.files获取要复制的所有文件/文件夹的列表(from,recursive = TRUE,all.files = TRUE,include.dirs = TRUE)
确定每个文件是文件,文件夹还是链接
从列表中删除链接文件夹的后代(因为链接后面是list.files)
复制文件夹,文件和链接(按此顺序)