---
title: "Comparison of fs functions, base R, and shell commands"
output: rmarkdown::html_vignette
vignette: >
  %\VignetteIndexEntry{base vs fs}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
---

```{r setup, include = FALSE}
knitr::opts_chunk$set(
  collapse = TRUE,
  comment = "#>"
)
```

Most of the functionality is **fs** can be approximated with functions in **base R**
or in a command line shell. The table at the end of this vignette can be used
as a translation aid between these three methods.

**fs** functions smooth over some of the idiosyncrasies of file handling with
base R functions:

* Vectorization. All **fs** functions are vectorized, accepting multiple paths
  as input. Base functions are inconsistently vectorized.

* Predictable return values that always convey a path. All **fs** functions
  return a character vector of paths, a named integer or a logical vector, where
  the names give the paths. Base return values are more varied: they are often
  logical or contain error codes which require downstream processing.

* Explicit failure. If **fs** operations fail, they throw an error. Base
  functions tend to generate a warning and a system dependent error code. This
  makes it easy to miss a failure.

* UTF-8 all the things. **fs** functions always convert input paths to UTF-8 and
  return results as UTF-8. This gives you path encoding consistency across OSes.
  Base functions rely on the native system encoding.

* Naming convention. **fs** functions use a consistent naming convention.
  Because base R's functions were gradually added over time there are a number
  of different conventions used (e.g. `path.expand()` vs `normalizePath()`;
  `Sys.chmod()` vs `file.access()`).

## Directory functions

| fs                                 | base                                                                    | shell                                |
| ---                                | ---                                                                     | ---                                  |
| `dir_ls("path")`                   | `list.files("path")`                                                    | `ls path`                            |
| `dir_info("path")`                 | `do.call(rbind, lapply(list.files("path"), file.info))`                 | `ls -al path`                        |
| `dir_copy("path", "new-path")`     | `dir.create("new-path"); file.copy("path", "new-path", recursive=TRUE)` | `cp path new-path`                   |
| `dir_create("path")`               | `dir.create("path")`                                                    | `mkdir path`                         |
| `dir_delete("path")`               | `unlink("path", recursive = TRUE)`                                      | `rm -rf path`                        |
| `dir_exists("path")`               | `dir.exists("path")`                                                    | `if [ -d "path" ]; then ... ; fi`    |
| ~~`dir_move()`~~ (see `file_move`) | `file.rename("path", "new-path")`                                       | `mv path new-path`                   |
| `dir_map("path", fun)`             | *No direct equivalent*                                                  | `for file in $(ls path); do ...; done` |
| `dir_tree("path")`                 | *No direct equivalent*                                                  | `tree path`                          |


## File functions

| fs                                          | base                              | shell                             |
| ---                                         | ---                               | ---                               |
| `file_chmod("path", "mode")`                | `Sys.chmod("path", "mode")`       | `chmod mode path`                 |
| `file_chown("path", "user_id", "group_id")` | *No direct equivalent*            | `chown options path `             |
| `file_copy("path", "new-path")`             | `file.copy("path", "new-path")`   | `cp path new-path`                |
| `file_create("new-path")`                   | `file.create("new-path")`         | `touch new-path`                  |
| `file_delete("path")`                       | `unlink("path")`                  | `rm path`                         |
| `file_exists("path")`                       | `file.exists("path")`             | `if [ -f "path" ]; then ... ; fi` |
| `file_info("path")`                         | `file.info("path")`               | `ls -al path`                     |
| `file_move("path", "new-path")`             | `file.rename("path", "new-path")` | `mv path new-path`                |
| `file_show("path")`                         | `browseURL("path")`               | `open path`                       |
| `file_touch()`                              | *No direct equivalent*            | `touch path`                      |
| `file_temp()`                               | `tempfile()`                      | `mktemp`                          |
| `file_test()`                               | *No direct equivalent*            | `if [ -d "path" ]; then ...; fi`  |

## Path functions

| fs                                                   | base                                              | shell                         |
| ---                                                  | ---                                               | ---                           |
| `path("top_dir", "nested_dir", "file", ext = "ext")` | `file.path("top_dir", "nested_dir", "file.ext")`  | `top_dir/nested_dir/file.ext` |
| `path_temp()`, `path_temp("path")`                   | `tempdir()`, `file.path(tempdir(), "path")`       | `mktemp -d`                   |
| `path_expand("~/path")`                              | `path.expand()`                                   | `realpath -m -s ~/path`       |
| `path_dir("path")`                                   | `dirname("path")`                                 | `dirname path`                |
| `path_file("path")`                                  | `basename("path")`                                | `basename path`               |
| `path_home()`                                        | `path.expand("~")`                                | `$HOME`                       |
| `path_package("pkgname", "dir", "file")`             | `system.file("dir", "file", package = "pkgname")` | *No direct equivalent*        |
| `path_norm("path")`                                  | `normalizePath()`                                 | `realpath`                    |
| `path_real("path")`                                  | `normalizePath(mustWork = TRUE)`                  | `realpath`                    |
| `path_rel("path/foo", "path/bar")`                   | *No direct equivalent*                            | *No direct equivalent*        |
| `path_common(c("path/foo", "path/bar", "path/baz"))` | *No direct equivalent*                            | *No direct equivalent*        |
| `path_ext_remove("path")`                            | `sub("\\.[a-zA-Z0-9]*$", "", "path")`             | *No direct equivalent*        |
| `path_ext_set("path", "new_ext")`                    | `sub("\\.[a-zA-Z0-9]*$", "new_ext", "path")`      | *No direct equivalent*        |
| `path_sanitize("path")`                              | *No direct equivalent*                            | *No direct equivalent*        |