How do I get the path to parent directory in R?
I have to write an R script that takes input from a directory in the parent directory and outputs data into another directory in the parent folder. So, if I could find path to parent folder, then I could do this.
You can use dirname on getwd to extract everything but the top most level of your current directory:
dirname(getwd())
[1] "C:/Documents and Settings"
Actually dirname allows to go back to several parent folders
Path="FolderA/FolderB/FolderC/FolderD"
dirname(Path)
"FolderA/FolderB/FolderC"
dirname(dirname(Path))
"FolderA/FolderB"
And so on...
I assume you mean parent directory of R's working directory?
The simplest solution is probably as follows.
wd <- getwd()
setwd("..")
parent <- getwd()
setwd(wd)
This saves the working directory, changes it to its parent, gets the result in parent, and resets the working directory again. This saves having to deal with the vagaries of root directories, home directories, and other OS-specific features, which would probably require a bunch of fiddling with regexes.
Possibly these two tips may help
"~/" # after the forward slash you "are" in your home folder
then on windows
"C:/" # you are in your main hard drive
"G:/" # you are just in another hard drive :-)
on unix you can do something similar with
"/etc/"
then you can go down into any sub directory you need
Or as #Hong Ooi suggests you can go up to the parent dir of your working directory with
"../"
NB: just after the final forward slash press tab and you'll have all the file and folder, very handy, especially in RStudio
Another possibility:
parts <- unlist(strsplit(getwd(), .Platform$file.sep))
do.call(file.path, as.list(parts[1:length(parts) - 1]))
This splits the filepath into directories, drops the last directory, and then recombines the parts into a filepath again.
You could simply use ".." like output_dir <- paste(input_dir, "..", "out", sep = .Platform$file.sep), or using the fs package (install.packages("fs")):
input_dir <- "base/input"
parent_dir <- fs::path(input_dir, "..") # "base/input/.."
output_dir <- fs::path(input_dir, "..", "out") # "base/input/../out"
# to shorten the path (avoid "input/../") you could use `fs::normalize`:
fs::normalize(fs::path(input_dir, "..", "out")) # "base/out"
# in case input is a symlink and you want the parent directory of the target, look at `fs::real`
In RStudio you could navigate to your code directory and "Set As Working Directory" in Files. And then ".." will work.
Related
In my main folder i have many sub folders like AA,BB,CC,DD ...etc. and all folders have a common script named run_script.R and i want to run this script in every folder. folder can be any amount.
Its working abut running in first folder only ,but i wanted it to run in every folder.
also when i am using setwd(folder) then showing error
Error in setwd(folder) : cannot change working directory
data_folder <- "C:/Users/mosho/Desktop/New folder (2)/"
allfolders <- data.frame(Folders = list.dirs(path = data_folder, recursive = F, full.names = F))
r_scripts <- "run_script.R"
for (folder in allfolders$Folders) {
#setwd(folder)
message(folder)
source(paste0(data_folder,folder,"/",r_scripts))
}
You are on a right path, I did some minor tweaks to your script which will resolve the issue. The points missing in your scripts are;
the allfolders contains the folder name not the entire explicit path. To set the working directory you need to set give the explicit path, by only calling the folder name will result into error unless you existing working directory is contains that folder. Anyways, its best practice to work with full path names.
also to simplify setting up allfolders as list for iterator will make your life lot easier than a data frame
Below is my work-out;
I created some dummy folders (DIC01, DIC02, DIC03...) under path "C:\Users\XXXXXX\Documents\TEST MAIN", and placed code run_script.R inside each one. This run_script.R contains simple code print("Hello World !!")
Next I set initial working directory where to the path where all the folders present i.e. to path "C:\Users\XXXXXX\Documents\TEST MAIN". Next listed the folders/directories present within this path as a list instead of data frame. Next is for loop which iterate over list of folder names. Inside we reset the working directory by the folder name and source the R code.
data_folder <- "C:\\Users\\XXXXXX\\Documents\\TEST MAIN"
setwd(data_folder)
allfolders <- list.dirs(path = data_folder, recursive = F, full.names = F)
r_scripts <- "run_script.R"
for (folder in allfolders) {
print(folder)
setwd(paste0(data_folder,"\\",folder))
source(paste0(data_folder,"\\",folder,"\\",r_scripts))
}
The result I get after the execution is something like this. First the name of the directory and then execution result.
I hope this resolves you problem. If yes Like/Up vote the answer and let me know.
Let's say my colleagues and I have a shared directory, such as a SharePoint drive. Our file path to any given directory, say OurProject1 will be the same with the only difference being our username.
So for example my path will be: "C:/Users/JohnLennon/SharedDrive/SharedData/baseline_data"
While theirs will be: "C:/Users/RingoStarr/SharedDrive/SharedData/baseline_data"
I am trying to write a function that will allow any of my colleagues who has mapped the shared drive to run a script that accesses data in the shared data without them having to manually input their username. Keep in mind that the project directory is not the shared drive - that if I share this script with a colleague it will be kept outside of the shared directory and so relative file paths with regards to the project won't work.
I have been trying to approach this using an absolute file path set temporarily within the function that infers the first half of the directory path from getwd(). So the function looks a bit like this:
wd <- getwd() # get the users working dir
usr <- substr(wd, 1, 18) # extract the root down to the username
paste(usr, "SharedDrive/SharedData/baseline_data", sep = "") # prefix this onto the shared directory path
This works fine for RingoStarr, who has the same number of characters in his username as JohnLennon, but what about GeorgeHarrison, or all the other users? Counting characters on line two is clearly a limited approach.
I am looking for a modification to line two that will navigate "blindly" from the working directory, which we assume to be a subdirectory of "C:/Users/Username/" to two levels below the root directory (i.e. in the Username directory). ".." won't work here as we don't know where abouts within the the Username directory getwd() is.
I am also open to a different approach to the problem if one exists
Instead of substr, you can try strsplit and then paste with the collapse argument:
wd_split <- strsplit(wd, "\\/")
wd_split
# [[1]]
# [1] "C:" "Users" "JohnLennon" "SharedDrive" "SharedData"
usr <- paste(wd_split[[1]][1:3], collapse = "/")
usr
# "C:/Users/JohnLennon"
I have an object called wanted.bam with the list of wanted file names for all the .bam (is the extension) files in three of my directories path1,path2,path3. I am looping over all these directories to search for the wanted files. What I am trying to do is look for wanted files by looping over each directory and implement a FUNCTION in each file. This loop works for all the matched file in the first directory, but as it progresses to another directory, it breaks giving an error:
Error in value[[3L]](cond) :
failed to open BamFile: file(s) do not exist:
'sort.bam'
my code:
bam.dir<- c("path1","path2","path3")
for (j in 1:length(bam.dir)){
all.bam.files <- list.files(bam.dir[j])
all.bam.files <- grep(wanted.names, all.bam.files, value=TRUE)
print(paste("The wanted number of bam files in this directory:", (length(all.bam.files))))
if(length(all.bam.files)==0){
next
}else{
setwd(bam.dir[j])
}
print(paste("The working directory number:",j,":",(getwd())))
## ****using another loop here for each file to implement a function*****
all.FAD<- {}
for(i in 1:length(all.bam.files)){
output<- FUNCTION(all.bam.files[i])
}
}
You probably don't want to be changing working directory like this. Instead, use the option in list.files, full.names=TRUE, to return the full path of your files. Then, you can just use read.csv, or whatever, on the full path name without need to change directory. Your code is failing because after you set directory, the relative path to the next directory is changed.
If you want to keep changing directories, just make sure you set the directory back to the base directory at the end of the loop.
In all other cases, when I am working within an RStudio project, I can make references relative to the project root in scripts. So I can, for example, dfX = read.csv("Data/somefile.csv"), where the folder Data is relative to my project root.
The same code in a knitr chunk does not find the file. I guess this is because knitr creates a bunch of temporary directories that it needs to refer to relative to the file location. Is there an easy way to change this behavior? Obviously, I would not like to add the entire path to the project folder -- I am aware that I can easily do this using knitr::opts_knit$set(root.dir = rootPath). That completely breaks maintainability across machines and OSs.
Edit: This seems closely linked to this question.
Presumably you know the path to the package directory when you call 'knit', so how about:
ENV <- new.env()
assign("workingDirectory", getcwd(), envir = ENV)
knitr::knit(...,
# THE ENVIRONMENT IN WHICH THE CODE CHUNKS ARE TO BE EVALUATED
envir=ENV)
Then in your rmd file you can do:
```{r] print(workingDirectory)```
If you're searching for the location of the current install, you can use:
PATH = NULL
for(libPath in .libPaths())
if('myPackage' %in% list.dirs(libPath,FALSE,FALSE)){
PATH = file.path(libPath,'myPackage')
}
if(is.null(PATH))
stop('could not find package directory')
ENV <- new.env()
assign("workingDirectory", PATH, envir = ENV)
knitr::knit(...,
# THE ENVIRONMENT IN WHICH THE CODE CHUNKS ARE TO BE EVALUATED
envir=ENV)
My guess is that the document that you are "knitting" is in a subdirectory itself. It seems that, when you click "Knit PDF", RStudio or knitr will setwd() to the directory containing the file being knitted. So you may need to do something like dfX = read.csv("../Data/somefile.csv") to get the reference right.
I have a working example here.
In R, I'm working on "./parent/Child/A". I want to move back parent folder "child", but when I type full path. It lost many times.
setwd('..')
will move up one directory without entering the absolute path. Here's an example
> getwd()
[1] "C:/Users/D/Desktop/EDABaseball"
> setwd('..')
> getwd()
[1] "C:/Users/D/Desktop"
I think you want to move back to the working directory ./parent/Child/. This can be done in 2 ways, assuming your current working directory is ./parent/Child/A
1) setwd("..")
2) setwd("./..")
3) setwd("./parent/Child")
I also find dirname() function pretty useful especially if your path is saved in a variable:
mypath <- getwd()
# The path of the parent directory:
dirname(mypath)
Moves up one directory in Linux
setwd("../")
Basically I split the child folder using strsplit by '/' and then got the parent folder pasting the slices collapsing by '/', except for the last one. I used getwd() to make the code reproducible, but you may use any folder.
myDir <- unlist(strsplit(getwd(), '/'))
paste0(myDir[-length(myDir)], collapse = '/')