# Copying folder including subfolders

**URL:** <https://discourse.julialang.org/t/copying-folder-including-subfolders/104065>\
**Category:** General Usage\
**Tags:** filesystem\
**Created:** [September 20, 2023, 1:55pm UTC](https://discourse.julialang.org/t/copying-folder-including-subfolders/104065 "2023-09-20T13:55:09Z")\
**Posts on this page:** 11\
**Page:** 1

<div class="post-metadata">

**Author:** ![wsshin](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/wsshin/32/360_2.png) [@wsshin](https://discourse.julialang.org/u/wsshin)\
**Post date:** [September 20, 2023, 1:55pm UTC](https://discourse.julialang.org/t/copying-folder-including-subfolders/104065/1 "2023-09-20T13:55:09Z")

</div>

Is there an easy way to copy the contents of one folder, including all subfolders, to another folder?

It seems that `cp()` supported the `recursive` keyword at [one point](https://github.com/JuliaLang/julia/pull/10448), but not anymore.

---

<div class="post-metadata">

**Author:** ![jd-foster](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jd-foster/32/35824_2.png) [@jd-foster](https://discourse.julialang.org/u/jd-foster)\
**Post date:** [September 20, 2023, 2:32pm UTC](https://discourse.julialang.org/t/copying-folder-including-subfolders/104065/2 "2023-09-20T14:32:53Z")

</div>

`Base.Filesystem.cptree("test", "test_copy")`

---

<div class="post-metadata">

**Author:** ![wsshin](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/wsshin/32/360_2.png) [@wsshin](https://discourse.julialang.org/u/wsshin)\
**Post date:** [September 20, 2023, 4:45pm UTC](https://discourse.julialang.org/t/copying-folder-including-subfolders/104065/3 "2023-09-20T16:45:24Z")

</div>

Thanks, but when the destination folder `dst` already exists, `cptree()` asks me to use the keyword argument `force=true`. This seems to remove the `dst` folder and then recreate it, instead of simply overwriting its contents. The `dst` folder contains extra files that don’t exist in `src`, and I want to keep them. Is there a way to overwrite the contents of `dst` without removing `dst` itself and recreating it?

---

<div class="post-metadata">

**Author:** ![schlichtanders](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/schlichtanders/32/32145_2.png) [@schlichtanders](https://discourse.julialang.org/u/schlichtanders)\
**Post date:** [October 25, 2024, 6:55am UTC](https://discourse.julialang.org/t/copying-folder-including-subfolders/104065/4 "2024-10-25T06:55:25Z")

</div>

I am also looking for the equivalent of bash’s cp command in julia. couldn’t find anything so far

---

<div class="post-metadata">

**Author:** ![ufechner7](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ufechner7/32/51363_2.png) [@ufechner7](https://discourse.julialang.org/u/ufechner7)\
**Post date:** [October 25, 2024, 7:12am UTC](https://discourse.julialang.org/t/copying-folder-including-subfolders/104065/5 "2024-10-25T07:12:24Z")

</div>

> [@schlichtanders](#):
>
> couldn’t find anything so far

Write a function that suits your needs yourself. So easy in Julia.

---

<div class="post-metadata">

**Author:** ![schlichtanders](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/schlichtanders/32/32145_2.png) [@schlichtanders](https://discourse.julialang.org/u/schlichtanders)\
**Post date:** [October 25, 2024, 8:12am UTC](https://discourse.julialang.org/t/copying-folder-including-subfolders/104065/6 "2024-10-25T08:12:47Z")

</div>

same holds for `mv` command and some others as well probably.  
It is surprising that the julia version is called the same but so different from the shell version…

It would be great if all those commands get a flag to switch to shell recursive behaviour.

---

<div class="post-metadata">

**Author:** ![cshen](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/cshen/32/217287_2.png) [@cshen](https://discourse.julialang.org/u/cshen)\
**Post date:** [October 25, 2024, 9:28am UTC](https://discourse.julialang.org/t/copying-folder-including-subfolders/104065/7 "2024-10-25T09:28:27Z")

</div>

Custom recursive behaviour on a folder structure can be obtained by using the `walkdir` iterator.

a nice trick when using `walkdir` is using something like `destdir = normpath(joinpath(dst, relpath(root, src)))` to obtain a mirror copy of the folder structure but starting from `dst` instead of `src`.

If the current folder being walked is `src/some/folder` (the `root` in the snippet above) you can check existence of `dst/some/folder` before doing any action. You can then check existence of single files: `isfile(joinpath(destdir, file))` where `file` is from the `files` list obtained from the `walkdir` iterator.

one especially handy feature of `walkdir` is that you can just invert it and use a bottom up approach.

---

<div class="post-metadata">

**Author:** ![Alexander-Barth](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/alexander-barth/32/3692_2.png) [@Alexander-Barth](https://discourse.julialang.org/u/Alexander-Barth)\
**Post date:** [April 14, 2025, 8:33am UTC](https://discourse.julialang.org/t/copying-folder-including-subfolders/104065/8 "2025-04-14T08:33:52Z")

</div>

For reference, here is one approach:

```julia
function cpdir(srcdir,dstdir;
               matching = (entry) -> true,
               matching_dir = matching,
               matching_file = matching)
    mkpath(dstdir)
    for f in readdir(srcdir)
        src_entry = joinpath(srcdir,f)
        dst_entry = joinpath(dstdir,f)
        if isfile(src_entry)
            if matching_file(f)
                cp(src_entry,dst_entry)
            end
        elseif isdir(src_entry)
            if matching_dir(f)
                # recursive call
                cpdir(src_entry,dst_entry;
                      matching, matching_dir, matching_file)
            end
        end
    end
end

```

Copying all directory `srcdir` to `dstdir`, here ignoring the `.git` directory and files ending with `.out` and `~`:

```julia
using Glob: ismatch, @fn_str
cpdir(srcdir,dstdir;
      matching_dir = !=(".git"),
      matching_file = e -> !ismatch(fn"*.out",e) && !ismatch(fn"*~",e))

```

Or without Glob

```julia
cpdir(srcdir,dstdir;                                                                                                                                                                
          matching_dir = !=(".git"),                                                                                                                                                    
          matching_file = e -> !endswith(e,".out") && !endswith(e,"~"))  

```

As @rafael.guerra mentioned, this code will not overwrite any files, but returns with an `ArgumentError` if a file already exists. See Rafaels’ comment below.

---

<div class="post-metadata">

**Author:** ![rafael.guerra](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rafael.guerra/32/216610_2.png) [@rafael.guerra](https://discourse.julialang.org/u/rafael.guerra)\
**Post date:** [April 16, 2025, 4:42pm UTC](https://discourse.julialang.org/t/copying-folder-including-subfolders/104065/9 "2025-04-16T16:42:53Z")

</div>

@Alexander-Barth, I tried your code on a Win11 PC but I get the error:

```julia
ERROR: ArgumentError: '.\destdir\file1.txt' exists. `force=true` is required to remove '.\destdir\file1.txt' before copying.

```

Adding the keyword `force=true` to the `cp()` function, it will replace the files in the destination folder & subfolders with those with the same name from the source folder & subfolders (which is OK, but worth mentioning), while preserving those that do not match.

On another note, your code looks in the subdirectories, but I cannot see how. Could you give me a hint? Cheers.

---

<div class="post-metadata">

**Author:** ![healyp](https://avatars.discourse-cdn.com/v4/letter/h/67e7ee/32.png) [@healyp](https://discourse.julialang.org/u/healyp)\
**Post date:** [April 16, 2025, 7:59pm UTC](https://discourse.julialang.org/t/copying-folder-including-subfolders/104065/10 "2025-04-16T19:59:55Z")

</div>

`cpdir()` has a recursive call.

---

<div class="post-metadata">

**Author:** ![rafael.guerra](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rafael.guerra/32/216610_2.png) [@rafael.guerra](https://discourse.julialang.org/u/rafael.guerra)\
**Post date:** [April 16, 2025, 8:02pm UTC](https://discourse.julialang.org/t/copying-folder-including-subfolders/104065/11 "2025-04-16T20:02:33Z")

</div>

Thanks @healyp, I totally overlooked that.
