# module FileUtils

Namespace for file utility methods for copying, moving, removing, etc.

## What’s Here¶ ↑

First, what’s elsewhere. Module FileUtils:

- Inherits from class Object.

- Supplements class File (but is not included or extended there).

Here, module FileUtils provides methods that are useful for:

- Creating.

- Deleting.

- Querying.

- Setting.

- Comparing.

- Copying.

- Moving.

- Options.

### Creating¶ ↑

- `::mkdir`: Creates directories.

- `::mkdir_p`, `::makedirs`, `::mkpath`: Creates directories, also creating ancestor directories as needed.

- `::link_entry`: Creates a hard link.

- `::ln`, `::link`: Creates hard links.

- `::ln_s`, `::symlink`: Creates symbolic links.

- `::ln_sf`: Creates symbolic links, overwriting if necessary.

- `::ln_sr`: Creates symbolic links relative to targets

### Deleting¶ ↑

- `::remove_dir`: Removes a directory and its descendants.

- `::remove_entry`: Removes an entry, including its descendants if it is a directory.

- `::remove_entry_secure`: Like `::remove_entry`, but removes securely.

- `::remove_file`: Removes a file entry.

- `::rm`, `::remove`: Removes entries.

- `::rm_f`, `::safe_unlink`: Like `::rm`, but removes forcibly.

- `::rm_r`: Removes entries and their descendants.

- `::rm_rf`, `::rmtree`: Like `::rm_r`, but removes forcibly.

- `::rmdir`: Removes directories.

### Querying¶ ↑

- `::pwd`, `::getwd`: Returns the path to the working directory.

- `::uptodate?`: Returns whether a given entry is newer than given other entries.

### Setting¶ ↑

- `::cd`, `::chdir`: Sets the working directory.

- `::chmod`: Sets permissions for an entry.

- `::chmod_R`: Sets permissions for an entry and its descendants.

- `::chown`: Sets the owner and group for entries.

- `::chown_R`: Sets the owner and group for entries and their descendants.

- `::touch`: Sets modification and access times for entries, creating if necessary.

### Comparing¶ ↑

- `::compare_file`, `::cmp`, `::identical?`: Returns whether two entries are identical.

- `::compare_stream`: Returns whether two streams are identical.

### Copying¶ ↑

- `::copy_entry`: Recursively copies an entry.

- `::copy_file`: Copies an entry.

- `::copy_stream`: Copies a stream.

- `::cp`, `::copy`: Copies files.

- `::cp_lr`: Recursively creates hard links.

- `::cp_r`: Recursively copies files, retaining mode, owner, and group.

- `::install`: Recursively copies files, optionally setting mode, owner, and group.

### Moving¶ ↑

- `::mv`, `::move`: Moves entries.

### Options¶ ↑

- `::collect_method`: Returns the names of methods that accept a given option.

- `::commands`: Returns the names of methods that accept options.

- `::have_option?`: Returns whether a given method accepts a given option.

- `::options`: Returns all option names.

- `::options_of`: Returns the names of the options for a given method.

## Path Arguments¶ ↑

Some methods in FileUtils accept path arguments, which are interpreted as paths to filesystem entries:

- If the argument is a string, that value is the path.

- If the argument has method `:to_path`, it is converted via that method.

- If the argument has method `:to_str`, it is converted via that method.

## About the Examples¶ ↑

Some examples here involve trees of file entries. For these, we sometimes display trees using the tree command-line utility, which is a recursive directory-listing utility that produces a depth-indented listing of files and directories.

We use a helper method to launch the command and control the format:

    def tree(dirpath = '.')
      command = "tree --noreport --charset=ascii #{dirpath}"
      system(command)
    end

To illustrate:

    tree('src0')
    # => src0
    #    |-- sub0
    #    |   |-- src0.txt
    #    |   `-- src1.txt
    #    `-- sub1
    #        |-- src2.txt
    #        `-- src3.txt

## Avoiding the TOCTTOU Vulnerability¶ ↑

For certain methods that recursively remove entries, there is a potential vulnerability called the Time-of-check to time-of-use, or TOCTTOU, vulnerability that can exist when:

- An ancestor directory of the entry at the target path is world writable; such directories include `/tmp`.

- The directory tree at the target path includes:

  - A world-writable descendant directory.

  - A symbolic link.

To avoid that vulnerability, you can use this method to remove entries:

- `FileUtils.remove_entry_secure`: removes recursively if the target path points to a directory.

Also available are these methods, each of which calls FileUtils.remove_entry_secure:

- `FileUtils.rm_r` with keyword argument `secure: true`.

- `FileUtils.rm_rf` with keyword argument `secure: true`.

Finally, this method for moving entries calls FileUtils.remove_entry_secure if the source and destination are on different file systems (which means that the “move” is really a copy and remove):

- `FileUtils.mv` with keyword argument `secure: true`.

Method FileUtils.remove_entry_secure removes securely by applying a special pre-process:

- If the target path points to a directory, this method uses methods `File#chown` and `File#chmod` in removing directories.

- The owner of the target directory should be either the current process or the super user (root).

WARNING: You must ensure that ALL parent directories cannot be moved by other untrusted users. For example, parent directories should not be owned by untrusted users, and should not be world writable except when the sticky bit is set.

For details of this security vulnerability, see Perl cases:

- CVE-2005-0448.

- CVE-2004-0452.

### Constants

VERSION

### Public Class Methods

cd(dir, verbose: nil) { |dir| ... } click to toggle source

Changes the working directory to the given `dir`, which should be interpretable as a path:

With no block given, changes the current directory to the directory at `dir`; returns zero:

    FileUtils.pwd # => "/rdoc/fileutils"
    FileUtils.cd('..')
    FileUtils.pwd # => "/rdoc"
    FileUtils.cd('fileutils')

With a block given, changes the current directory to the directory at `dir`, calls the block with argument `dir`, and restores the original current directory; returns the block’s value:

    FileUtils.pwd                                     # => "/rdoc/fileutils"
    FileUtils.cd('..') { |arg| [arg, FileUtils.pwd] } # => ["..", "/rdoc"]
    FileUtils.pwd                                     # => "/rdoc/fileutils"

Keyword arguments:

- `verbose: true` - prints an equivalent command:

      FileUtils.cd('..')
      FileUtils.cd('fileutils')

  Output:

      cd ..
      cd fileutils

Related: `FileUtils.pwd`.

    # File lib/fileutils.rb, line 238
    def cd(dir, verbose: nil, &block) # :yield: dir
      fu_output_message "cd #{dir}" if verbose
      result = Dir.chdir(dir, &block)
      fu_output_message 'cd -' if verbose and block
      result
    end

Also aliased as: chdir
chdir(dir, verbose: nil)
Alias for: cd
chmod(mode, list, noop: nil, verbose: nil) click to toggle source

Changes permissions on the entries at the paths given in `list` (a single path or an array of paths) to the permissions given by `mode`; returns `list` if it is an array, `[list]` otherwise:

- Modifies each entry that is a regular file using `File.chmod`.

- Modifies each entry that is a symbolic link using `File.lchmod`.

Argument `list` or its elements should be interpretable as paths.

Argument `mode` may be either an integer or a string:

- Integer `mode`: represents the permission bits to be set:

      FileUtils.chmod(0755, 'src0.txt')
      FileUtils.chmod(0644, ['src0.txt', 'src0.dat'])

- String `mode`: represents the permissions to be set:

  The string is of the form `[targets][[operator][perms[,perms]]`, where:

  - `targets` may be any combination of these letters:

    - `'u'`: permissions apply to the file’s owner.

    - `'g'`: permissions apply to users in the file’s group.

    - `'o'`: permissions apply to other users not in the file’s group.

    - `'a'` (the default): permissions apply to all users.

  - `operator` may be one of these letters:

    - `'+'`: adds permissions.

    - `'-'`: removes permissions.

    - `'='`: sets (replaces) permissions.

  - `perms` (may be repeated, with separating commas) may be any combination of these letters:

    - `'r'`: Read.

    - `'w'`: Write.

    - `'x'`: Execute (search, for a directory).

    - `'X'`: Search (for a directories only; must be used with `'+'`)

    - `'s'`: Uid or gid.

    - `'t'`: Sticky bit.

  Examples:

      FileUtils.chmod('u=wrx,go=rx', 'src1.txt')
      FileUtils.chmod('u=wrx,go=rx', '/usr/bin/ruby')

Keyword arguments:

- `noop: true` - does not change permissions; returns `nil`.

- `verbose: true` - prints an equivalent command:

      FileUtils.chmod(0755, 'src0.txt', noop: true, verbose: true)
      FileUtils.chmod(0644, ['src0.txt', 'src0.dat'], noop: true, verbose: true)
      FileUtils.chmod('u=wrx,go=rx', 'src1.txt', noop: true, verbose: true)
      FileUtils.chmod('u=wrx,go=rx', '/usr/bin/ruby', noop: true, verbose: true)

  Output:

      chmod 755 src0.txt
      chmod 644 src0.txt src0.dat
      chmod u=wrx,go=rx src1.txt
      chmod u=wrx,go=rx /usr/bin/ruby

Related: `FileUtils.chmod_R`.

    # File lib/fileutils.rb, line 1803
    def chmod(mode, list, noop: nil, verbose: nil)
      list = fu_list(list)
      fu_output_message sprintf('chmod %s %s', mode_to_s(mode), list.join(' ')) if verbose
      return if noop
      list.each do |path|
        Entry_.new(path).chmod(fu_mode(mode, path))
      end
    end

chmod_R(mode, list, noop: nil, verbose: nil, force: nil) click to toggle source

Like `FileUtils.chmod`, but changes permissions recursively.

    # File lib/fileutils.rb, line 1815
    def chmod_R(mode, list, noop: nil, verbose: nil, force: nil)
      list = fu_list(list)
      fu_output_message sprintf('chmod -R%s %s %s',
                                (force ? 'f' : ''),
                                mode_to_s(mode), list.join(' ')) if verbose
      return if noop
      list.each do |root|
        Entry_.new(root).traverse do |ent|
          begin
            ent.chmod(fu_mode(mode, ent.path))
          rescue
            raise unless force
          end
        end
      end
    end

chown(user, group, list, noop: nil, verbose: nil) click to toggle source

Changes the owner and group on the entries at the paths given in `list` (a single path or an array of paths) to the given `user` and `group`; returns `list` if it is an array, `[list]` otherwise:

- Modifies each entry that is a regular file using `File.chown`.

- Modifies each entry that is a symbolic link using `File.lchown`.

Argument `list` or its elements should be interpretable as paths.

User and group:

- Argument `user` may be a user name or a user id; if `nil` or `-1`, the user is not changed.

- Argument `group` may be a group name or a group id; if `nil` or `-1`, the group is not changed.

- The user must be a member of the group.

Examples:

    # One path.
    # User and group as string names.
    File.stat('src0.txt').uid # => 1004
    File.stat('src0.txt').gid # => 1004
    FileUtils.chown('user2', 'group1', 'src0.txt')
    File.stat('src0.txt').uid # => 1006
    File.stat('src0.txt').gid # => 1005

    # User and group as uid and gid.
    FileUtils.chown(1004, 1004, 'src0.txt')
    File.stat('src0.txt').uid # => 1004
    File.stat('src0.txt').gid # => 1004

    # Array of paths.
    FileUtils.chown(1006, 1005, ['src0.txt', 'src0.dat'])

    # Directory (not recursive).
    FileUtils.chown('user2', 'group1', '.')

Keyword arguments:

- `noop: true` - does not change permissions; returns `nil`.

- `verbose: true` - prints an equivalent command:

      FileUtils.chown('user2', 'group1', 'src0.txt', noop: true, verbose: true)
      FileUtils.chown(1004, 1004, 'src0.txt', noop: true, verbose: true)
      FileUtils.chown(1006, 1005, ['src0.txt', 'src0.dat'], noop: true, verbose: true)
      FileUtils.chown('user2', 'group1', path, noop: true, verbose: true)
      FileUtils.chown('user2', 'group1', '.', noop: true, verbose: true)

  Output:

      chown user2:group1 src0.txt
      chown 1004:1004 src0.txt
      chown 1006:1005 src0.txt src0.dat
      chown user2:group1 src0.txt
      chown user2:group1 .

Related: `FileUtils.chown_R`.

    # File lib/fileutils.rb, line 1896
    def chown(user, group, list, noop: nil, verbose: nil)
      list = fu_list(list)
      fu_output_message sprintf('chown %s %s',
                                (group ? "#{user}:#{group}" : user || ':'),
                                list.join(' ')) if verbose
      return if noop
      uid = fu_get_uid(user)
      gid = fu_get_gid(group)
      list.each do |path|
        Entry_.new(path).chown uid, gid
      end
    end

chown_R(user, group, list, noop: nil, verbose: nil, force: nil) click to toggle source

Like `FileUtils.chown`, but changes owner and group recursively.

    # File lib/fileutils.rb, line 1912
    def chown_R(user, group, list, noop: nil, verbose: nil, force: nil)
      list = fu_list(list)
      fu_output_message sprintf('chown -R%s %s %s',
                                (force ? 'f' : ''),
                                (group ? "#{user}:#{group}" : user || ':'),
                                list.join(' ')) if verbose
      return if noop
      uid = fu_get_uid(user)
      gid = fu_get_gid(group)
      list.each do |root|
        Entry_.new(root).traverse do |ent|
          begin
            ent.chown uid, gid
          rescue
            raise unless force
          end
        end
      end
    end

cmp(a, b)
Alias for: compare_file
collect_method(opt) click to toggle source

Returns an array of the string method names of the methods that accept the given keyword option `opt`; the argument must be a symbol:

    FileUtils.collect_method(:preserve) # => ["cp", "copy", "cp_r", "install"]

    # File lib/fileutils.rb, line 2609
    def self.collect_method(opt)
      OPT_TABLE.keys.select {|m| OPT_TABLE[m].include?(opt) }
    end

commands() click to toggle source

Returns an array of the string names of FileUtils methods that accept one or more keyword arguments:

    FileUtils.commands.sort.take(3) # => ["cd", "chdir", "chmod"]

    # File lib/fileutils.rb, line 2570
    def self.commands
      OPT_TABLE.keys
    end

compare_file(a, b) click to toggle source

Returns `true` if the contents of files `a` and `b` are identical, `false` otherwise.

Arguments `a` and `b` should be interpretable as a path.

`FileUtils.identical?` and `FileUtils.cmp` are aliases for `FileUtils.compare_file`.

Related: `FileUtils.compare_stream`.

    # File lib/fileutils.rb, line 1507
    def compare_file(a, b)
      return false unless File.size(a) == File.size(b)
      File.open(a, 'rb') {|fa|
        File.open(b, 'rb') {|fb|
          return compare_stream(fa, fb)
        }
      }
    end

Also aliased as: identical?, cmp
compare_stream(a, b) click to toggle source

Returns `true` if the contents of streams `a` and `b` are identical, `false` otherwise.

Arguments `a` and `b` should be interpretable as a path.

Related: `FileUtils.compare_file`.

    # File lib/fileutils.rb, line 1530
    def compare_stream(a, b)
      bsize = fu_stream_blksize(a, b)

      sa = String.new(capacity: bsize)
      sb = String.new(capacity: bsize)

      begin
        a.read(bsize, sa)
        b.read(bsize, sb)
        return true if sa.empty? && sb.empty?
      end while sa == sb
      false
    end

copy(src, dest, preserve: nil, noop: nil, verbose: nil)
Alias for: cp
copy_entry(src, dest, preserve = false, dereference_root = false, remove_destination = false) click to toggle source

Recursively copies files from `src` to `dest`.

Arguments `src` and `dest` should be interpretable as paths.

If `src` is the path to a file, copies `src` to `dest`:

    FileUtils.touch('src0.txt')
    File.exist?('dest0.txt') # => false
    FileUtils.copy_entry('src0.txt', 'dest0.txt')
    File.file?('dest0.txt')  # => true

If `src` is a directory, recursively copies `src` to `dest`:

    tree('src1')
    # => src1
    #    |-- dir0
    #    |   |-- src0.txt
    #    |   `-- src1.txt
    #    `-- dir1
    #        |-- src2.txt
    #        `-- src3.txt
    FileUtils.copy_entry('src1', 'dest1')
    tree('dest1')
    # => dest1
    #    |-- dir0
    #    |   |-- src0.txt
    #    |   `-- src1.txt
    #    `-- dir1
    #        |-- src2.txt
    #        `-- src3.txt

The recursive copying preserves file types for regular files, directories, and symbolic links; other file types (FIFO streams, device files, etc.) are not supported.

Keyword arguments:

- `dereference_root: true` - if `src` is a symbolic link, follows the link.

- `preserve: true` - preserves file times.

- `remove_destination: true` - removes `dest` before copying files.

Related: methods for copying.

    # File lib/fileutils.rb, line 1040
    def copy_entry(src, dest, preserve = false, dereference_root = false, remove_destination = false)
      if dereference_root
        src = File.realpath(src)
      end

      Entry_.new(src, nil, false).wrap_traverse(proc do |ent|
        destent = Entry_.new(dest, ent.rel, false)
        File.unlink destent.path if remove_destination && (File.file?(destent.path) || File.symlink?(destent.path))
        ent.copy destent.path
      end, proc do |ent|
        destent = Entry_.new(dest, ent.rel, false)
        ent.copy_metadata destent.path if preserve
      end)
    end

copy_file(src, dest, preserve = false, dereference = true) click to toggle source

Copies file from `src` to `dest`, which should not be directories.

Arguments `src` and `dest` should be interpretable as paths.

Examples:

    FileUtils.touch('src0.txt')
    FileUtils.copy_file('src0.txt', 'dest0.txt')
    File.file?('dest0.txt') # => true

Keyword arguments:

- `dereference: false` - if `src` is a symbolic link, does not follow the link.

- `preserve: true` - preserves file times.

- `remove_destination: true` - removes `dest` before copying files.

Related: methods for copying.

    # File lib/fileutils.rb, line 1076
    def copy_file(src, dest, preserve = false, dereference = true)
      ent = Entry_.new(src, nil, dereference)
      ent.copy_file dest
      ent.copy_metadata dest if preserve
    end

copy_stream(src, dest) click to toggle source

Copies IO stream `src` to IO stream `dest` via `IO.copy_stream`.

Related: methods for copying.

    # File lib/fileutils.rb, line 1088
    def copy_stream(src, dest)
      IO.copy_stream(src, dest)
    end

cp(src, dest, preserve: nil, noop: nil, verbose: nil) click to toggle source

Copies files.

Arguments `src` (a single path or an array of paths) and `dest` (a single path) should be interpretable as paths.

If `src` is the path to a file and `dest` is not the path to a directory, copies `src` to `dest`:

    FileUtils.touch('src0.txt')
    File.exist?('dest0.txt') # => false
    FileUtils.cp('src0.txt', 'dest0.txt')
    File.file?('dest0.txt')  # => true

If `src` is the path to a file and `dest` is the path to a directory, copies `src` to `dest/src`:

    FileUtils.touch('src1.txt')
    FileUtils.mkdir('dest1')
    FileUtils.cp('src1.txt', 'dest1')
    File.file?('dest1/src1.txt') # => true

If `src` is an array of paths to files and `dest` is the path to a directory, copies from each `src` to `dest`:

    src_file_paths = ['src2.txt', 'src2.dat']
    FileUtils.touch(src_file_paths)
    FileUtils.mkdir('dest2')
    FileUtils.cp(src_file_paths, 'dest2')
    File.file?('dest2/src2.txt') # => true
    File.file?('dest2/src2.dat') # => true

Keyword arguments:

- `preserve: true` - preserves file times.

- `noop: true` - does not copy files.

- `verbose: true` - prints an equivalent command:

      FileUtils.cp('src0.txt', 'dest0.txt', noop: true, verbose: true)
      FileUtils.cp('src1.txt', 'dest1', noop: true, verbose: true)
      FileUtils.cp(src_file_paths, 'dest2', noop: true, verbose: true)

  Output:

      cp src0.txt dest0.txt
      cp src1.txt dest1
      cp src2.txt src2.dat dest2

Raises an exception if `src` is a directory.

Related: methods for copying.

    # File lib/fileutils.rb, line 873
    def cp(src, dest, preserve: nil, noop: nil, verbose: nil)
      fu_output_message "cp#{preserve ? ' -p' : ''} #{[src,dest].flatten.join ' '}" if verbose
      return if noop
      fu_each_src_dest(src, dest) do |s, d|
        copy_file s, d, preserve
      end
    end

Also aliased as: copy
cp_lr(src, dest, noop: nil, verbose: nil, dereference_root: true, remove_destination: false) click to toggle source

Creates hard links.

Arguments `src` (a single path or an array of paths) and `dest` (a single path) should be interpretable as paths.

If `src` is the path to a directory and `dest` does not exist, creates links `dest` and descendents pointing to `src` and its descendents:

    tree('src0')
    # => src0
    #    |-- sub0
    #    |   |-- src0.txt
    #    |   `-- src1.txt
    #    `-- sub1
    #        |-- src2.txt
    #        `-- src3.txt
    File.exist?('dest0') # => false
    FileUtils.cp_lr('src0', 'dest0')
    tree('dest0')
    # => dest0
    #    |-- sub0
    #    |   |-- src0.txt
    #    |   `-- src1.txt
    #    `-- sub1
    #        |-- src2.txt
    #        `-- src3.txt

If `src` and `dest` are both paths to directories, creates links `dest/src` and descendents pointing to `src` and its descendents:

    tree('src1')
    # => src1
    #    |-- sub0
    #    |   |-- src0.txt
    #    |   `-- src1.txt
    #    `-- sub1
    #        |-- src2.txt
    #        `-- src3.txt
    FileUtils.mkdir('dest1')
    FileUtils.cp_lr('src1', 'dest1')
    tree('dest1')
    # => dest1
    #    `-- src1
    #        |-- sub0
    #        |   |-- src0.txt
    #        |   `-- src1.txt
    #        `-- sub1
    #            |-- src2.txt
    #            `-- src3.txt

If `src` is an array of paths to entries and `dest` is the path to a directory, for each path `filepath` in `src`, creates a link at `dest/filepath` pointing to that path:

    tree('src2')
    # => src2
    #    |-- sub0
    #    |   |-- src0.txt
    #    |   `-- src1.txt
    #    `-- sub1
    #        |-- src2.txt
    #        `-- src3.txt
    FileUtils.mkdir('dest2')
    FileUtils.cp_lr(['src2/sub0', 'src2/sub1'], 'dest2')
    tree('dest2')
    # => dest2
    #    |-- sub0
    #    |   |-- src0.txt
    #    |   `-- src1.txt
    #    `-- sub1
    #        |-- src2.txt
    #        `-- src3.txt

Keyword arguments:

- `dereference_root: false` - if `src` is a symbolic link, does not dereference it.

- `noop: true` - does not create links.

- `remove_destination: true` - removes `dest` before creating links.

- `verbose: true` - prints an equivalent command:

      FileUtils.cp_lr('src0', 'dest0', noop: true, verbose: true)
      FileUtils.cp_lr('src1', 'dest1', noop: true, verbose: true)
      FileUtils.cp_lr(['src2/sub0', 'src2/sub1'], 'dest2', noop: true, verbose: true)

  Output:

      cp -lr src0 dest0
      cp -lr src1 dest1
      cp -lr src2/sub0 src2/sub1 dest2

Raises an exception if `dest` is the path to an existing file or directory and keyword argument `remove_destination: true` is not given.

Related: methods for copying.

    # File lib/fileutils.rb, line 627
    def cp_lr(src, dest, noop: nil, verbose: nil,
              dereference_root: true, remove_destination: false)
      fu_output_message "cp -lr#{remove_destination ? ' --remove-destination' : ''} #{[src,dest].flatten.join ' '}" if verbose
      return if noop
      fu_each_src_dest(src, dest) do |s, d|
        link_entry s, d, dereference_root, remove_destination
      end
    end

cp_r(src, dest, preserve: nil, noop: nil, verbose: nil, dereference_root: true, remove_destination: nil) click to toggle source

Recursively copies files.

Arguments `src` (a single path or an array of paths) and `dest` (a single path) should be interpretable as paths.

The mode, owner, and group are retained in the copy; to change those, use `FileUtils.install` instead.

If `src` is the path to a file and `dest` is not the path to a directory, copies `src` to `dest`:

    FileUtils.touch('src0.txt')
    File.exist?('dest0.txt') # => false
    FileUtils.cp_r('src0.txt', 'dest0.txt')
    File.file?('dest0.txt')  # => true

If `src` is the path to a file and `dest` is the path to a directory, copies `src` to `dest/src`:

    FileUtils.touch('src1.txt')
    FileUtils.mkdir('dest1')
    FileUtils.cp_r('src1.txt', 'dest1')
    File.file?('dest1/src1.txt') # => true

If `src` is the path to a directory and `dest` does not exist, recursively copies `src` to `dest`:

    tree('src2')
    # => src2
    #    |-- dir0
    #    |   |-- src0.txt
    #    |   `-- src1.txt
    #    `-- dir1
    #    |-- src2.txt
    #    `-- src3.txt
    FileUtils.exist?('dest2') # => false
    FileUtils.cp_r('src2', 'dest2')
    tree('dest2')
    # => dest2
    #    |-- dir0
    #    |   |-- src0.txt
    #    |   `-- src1.txt
    #    `-- dir1
    #    |-- src2.txt
    #    `-- src3.txt

If `src` and `dest` are paths to directories, recursively copies `src` to `dest/src`:

    tree('src3')
    # => src3
    #    |-- dir0
    #    |   |-- src0.txt
    #    |   `-- src1.txt
    #    `-- dir1
    #    |-- src2.txt
    #    `-- src3.txt
    FileUtils.mkdir('dest3')
    FileUtils.cp_r('src3', 'dest3')
    tree('dest3')
    # => dest3
    #    `-- src3
    #      |-- dir0
    #      |   |-- src0.txt
    #      |   `-- src1.txt
    #      `-- dir1
    #          |-- src2.txt
    #          `-- src3.txt

If `src` is an array of paths and `dest` is a directory, recursively copies from each path in `src` to `dest`; the paths in `src` may point to files and/or directories.

Keyword arguments:

- `dereference_root: false` - if `src` is a symbolic link, does not dereference it.

- `noop: true` - does not copy files.

- `preserve: true` - preserves file times.

- `remove_destination: true` - removes `dest` before copying files.

- `verbose: true` - prints an equivalent command:

      FileUtils.cp_r('src0.txt', 'dest0.txt', noop: true, verbose: true)
      FileUtils.cp_r('src1.txt', 'dest1', noop: true, verbose: true)
      FileUtils.cp_r('src2', 'dest2', noop: true, verbose: true)
      FileUtils.cp_r('src3', 'dest3', noop: true, verbose: true)

  Output:

      cp -r src0.txt dest0.txt
      cp -r src1.txt dest1
      cp -r src2 dest2
      cp -r src3 dest3

Raises an exception of `src` is the path to a directory and `dest` is the path to a file.

Related: methods for copying.

    # File lib/fileutils.rb, line 985
    def cp_r(src, dest, preserve: nil, noop: nil, verbose: nil,
             dereference_root: true, remove_destination: nil)
      fu_output_message "cp -r#{preserve ? 'p' : ''}#{remove_destination ? ' --remove-destination' : ''} #{[src,dest].flatten.join ' '}" if verbose
      return if noop
      fu_each_src_dest(src, dest) do |s, d|
        copy_entry s, d, preserve, dereference_root, remove_destination
      end
    end

getwd()
Alias for: pwd
have_option?(mid, opt) click to toggle source

Returns `true` if method `mid` accepts the given option `opt`, `false` otherwise; the arguments may be strings or symbols:

    FileUtils.have_option?(:chmod, :noop) # => true
    FileUtils.have_option?('chmod', 'secure') # => false

    # File lib/fileutils.rb, line 2588
    def self.have_option?(mid, opt)
      li = OPT_TABLE[mid.to_s] or raise ArgumentError, "no such method: #{mid}"
      li.include?(opt)
    end

identical?(a, b)
Alias for: compare_file
install(src, dest, mode: nil, owner: nil, group: nil, preserve: nil, noop: nil, verbose: nil) click to toggle source

Copies a file entry. See install(1).

Arguments `src` (a single path or an array of paths) and `dest` (a single path) should be interpretable as paths;

If the entry at `dest` does not exist, copies from `src` to `dest`:

    File.read('src0.txt')    # => "aaa\n"
    File.exist?('dest0.txt') # => false
    FileUtils.install('src0.txt', 'dest0.txt')
    File.read('dest0.txt')   # => "aaa\n"

If `dest` is a file entry, copies from `src` to `dest`, overwriting:

    File.read('src1.txt')  # => "aaa\n"
    File.read('dest1.txt') # => "bbb\n"
    FileUtils.install('src1.txt', 'dest1.txt')
    File.read('dest1.txt') # => "aaa\n"

If `dest` is a directory entry, copies from `src` to `dest/src`, overwriting if necessary:

    File.read('src2.txt')       # => "aaa\n"
    File.read('dest2/src2.txt') # => "bbb\n"
    FileUtils.install('src2.txt', 'dest2')
    File.read('dest2/src2.txt') # => "aaa\n"

If `src` is an array of paths and `dest` points to a directory, copies each path `path` in `src` to `dest/path`:

    File.file?('src3.txt') # => true
    File.file?('src3.dat') # => true
    FileUtils.mkdir('dest3')
    FileUtils.install(['src3.txt', 'src3.dat'], 'dest3')
    File.file?('dest3/src3.txt') # => true
    File.file?('dest3/src3.dat') # => true

Keyword arguments:

- `group: group` - changes the group if not `nil`, using `File.chown`.

- `mode: permissions` - changes the permissions. using `File.chmod`.

- `noop: true` - does not copy entries; returns `nil`.

- `owner: owner` - changes the owner if not `nil`, using `File.chown`.

- `preserve: true` - preserve timestamps using `File.utime`.

- `verbose: true` - prints an equivalent command:

      FileUtils.install('src0.txt', 'dest0.txt', noop: true, verbose: true)
      FileUtils.install('src1.txt', 'dest1.txt', noop: true, verbose: true)
      FileUtils.install('src2.txt', 'dest2', noop: true, verbose: true)

  Output:

      install -c src0.txt dest0.txt
      install -c src1.txt dest1.txt
      install -c src2.txt dest2

Related: methods for copying.

    # File lib/fileutils.rb, line 1609
    def install(src, dest, mode: nil, owner: nil, group: nil, preserve: nil,
                noop: nil, verbose: nil)
      if verbose
        msg = +"install -c"
        msg << ' -p' if preserve
        msg << ' -m ' << mode_to_s(mode) if mode
        msg << " -o #{owner}" if owner
        msg << " -g #{group}" if group
        msg << ' ' << [src,dest].flatten.join(' ')
        fu_output_message msg
      end
      return if noop
      uid = fu_get_uid(owner)
      gid = fu_get_gid(group)
      fu_each_src_dest(src, dest) do |s, d|
        st = File.stat(s)
        unless File.exist?(d) and compare_file(s, d)
          remove_file d, true
          if d.end_with?('/')
            mkdir_p d
            copy_file s, d + File.basename(s)
          else
            mkdir_p File.expand_path('..', d)
            copy_file s, d
          end
          File.utime st.atime, st.mtime, d if preserve
          File.chmod fu_mode(mode, st), d if mode
          File.chown uid, gid, d if uid or gid
        end
      end
    end

link(src, dest, force: nil, noop: nil, verbose: nil)
Alias for: ln
link_entry(src, dest, dereference_root = false, remove_destination = false) click to toggle source

Creates hard links; returns `nil`.

Arguments `src` and `dest` should be interpretable as paths.

If `src` is the path to a file and `dest` does not exist, creates a hard link at `dest` pointing to `src`:

    FileUtils.touch('src0.txt')
    File.exist?('dest0.txt') # => false
    FileUtils.link_entry('src0.txt', 'dest0.txt')
    File.file?('dest0.txt')  # => true

If `src` is the path to a directory and `dest` does not exist, recursively creates hard links at `dest` pointing to paths in `src`:

    FileUtils.mkdir_p(['src1/dir0', 'src1/dir1'])
    src_file_paths = [
      'src1/dir0/t0.txt',
      'src1/dir0/t1.txt',
      'src1/dir1/t2.txt',
      'src1/dir1/t3.txt',
      ]
    FileUtils.touch(src_file_paths)
    File.directory?('dest1')        # => true
    FileUtils.link_entry('src1', 'dest1')
    File.file?('dest1/dir0/t0.txt') # => true
    File.file?('dest1/dir0/t1.txt') # => true
    File.file?('dest1/dir1/t2.txt') # => true
    File.file?('dest1/dir1/t3.txt') # => true

Keyword arguments:

- `dereference_root: true` - dereferences `src` if it is a symbolic link.

- `remove_destination: true` - removes `dest` before creating links.

Raises an exception if `dest` is the path to an existing file or directory and keyword argument `remove_destination: true` is not given.

Related: `FileUtils.ln` (has different options).

    # File lib/fileutils.rb, line 812
    def link_entry(src, dest, dereference_root = false, remove_destination = false)
      Entry_.new(src, nil, dereference_root).traverse do |ent|
        destent = Entry_.new(dest, ent.rel, false)
        File.unlink destent.path if remove_destination && File.file?(destent.path)
        ent.link destent.path
      end
    end

ln(src, dest, force: nil, noop: nil, verbose: nil) click to toggle source

Creates hard links.

Arguments `src` (a single path or an array of paths) and `dest` (a single path) should be interpretable as paths.

When `src` is the path to an existing file and `dest` is the path to a non-existent file, creates a hard link at `dest` pointing to `src`; returns zero:

    Dir.children('tmp0/')                    # => ["t.txt"]
    Dir.children('tmp1/')                    # => []
    FileUtils.ln('tmp0/t.txt', 'tmp1/t.lnk') # => 0
    Dir.children('tmp1/')                    # => ["t.lnk"]

When `src` is the path to an existing file and `dest` is the path to an existing directory, creates a hard link at `dest/src` pointing to `src`; returns zero:

    Dir.children('tmp2')               # => ["t.dat"]
    Dir.children('tmp3')               # => []
    FileUtils.ln('tmp2/t.dat', 'tmp3') # => 0
    Dir.children('tmp3')               # => ["t.dat"]

When `src` is an array of paths to existing files and `dest` is the path to an existing directory, then for each path `target` in `src`, creates a hard link at `dest/target` pointing to `target`; returns `src`:

    Dir.children('tmp4/')                               # => []
    FileUtils.ln(['tmp0/t.txt', 'tmp2/t.dat'], 'tmp4/') # => ["tmp0/t.txt", "tmp2/t.dat"]
    Dir.children('tmp4/')                               # => ["t.dat", "t.txt"]

Keyword arguments:

- `force: true` - overwrites `dest` if it exists.

- `noop: true` - does not create links.

- `verbose: true` - prints an equivalent command:

      FileUtils.ln('tmp0/t.txt', 'tmp1/t.lnk', verbose: true)
      FileUtils.ln('tmp2/t.dat', 'tmp3', verbose: true)
      FileUtils.ln(['tmp0/t.txt', 'tmp2/t.dat'], 'tmp4/', verbose: true)

  Output:

      ln tmp0/t.txt tmp1/t.lnk
      ln tmp2/t.dat tmp3
      ln tmp0/t.txt tmp2/t.dat tmp4/

Raises an exception if `dest` is the path to an existing file and keyword argument `force` is not `true`.

Related: `FileUtils.link_entry` (has different options).

    # File lib/fileutils.rb, line 516
    def ln(src, dest, force: nil, noop: nil, verbose: nil)
      fu_output_message "ln#{force ? ' -f' : ''} #{[src,dest].flatten.join ' '}" if verbose
      return if noop
      fu_each_src_dest0(src, dest) do |s,d|
        remove_file d, true if force
        File.link s, d
      end
    end

Also aliased as: link
ln_s(src, dest, force: nil, relative: false, target_directory: true, noop: nil, verbose: nil) click to toggle source

Creates symbolic links.

Arguments `src` (a single path or an array of paths) and `dest` (a single path) should be interpretable as paths.

If `src` is the path to an existing file:

- When `dest` is the path to a non-existent file, creates a symbolic link at `dest` pointing to `src`:

      FileUtils.touch('src0.txt')
      File.exist?('dest0.txt')   # => false
      FileUtils.ln_s('src0.txt', 'dest0.txt')
      File.symlink?('dest0.txt') # => true

- When `dest` is the path to an existing file, creates a symbolic link at `dest` pointing to `src` if and only if keyword argument `force: true` is given (raises an exception otherwise):

      FileUtils.touch('src1.txt')
      FileUtils.touch('dest1.txt')
      FileUtils.ln_s('src1.txt', 'dest1.txt', force: true)
      FileTest.symlink?('dest1.txt') # => true

      FileUtils.ln_s('src1.txt', 'dest1.txt') # Raises Errno::EEXIST.

If `dest` is the path to a directory, creates a symbolic link at `dest/src` pointing to `src`:

    FileUtils.touch('src2.txt')
    FileUtils.mkdir('destdir2')
    FileUtils.ln_s('src2.txt', 'destdir2')
    File.symlink?('destdir2/src2.txt') # => true

If `src` is an array of paths to existing files and `dest` is a directory, for each child `child` in `src` creates a symbolic link `dest/child` pointing to `child`:

    FileUtils.mkdir('srcdir3')
    FileUtils.touch('srcdir3/src0.txt')
    FileUtils.touch('srcdir3/src1.txt')
    FileUtils.mkdir('destdir3')
    FileUtils.ln_s(['srcdir3/src0.txt', 'srcdir3/src1.txt'], 'destdir3')
    File.symlink?('destdir3/src0.txt') # => true
    File.symlink?('destdir3/src1.txt') # => true

Keyword arguments:

- `force: true` - overwrites `dest` if it exists.

- `relative: false` - create links relative to `dest`.

- `noop: true` - does not create links.

- `verbose: true` - prints an equivalent command:

      FileUtils.ln_s('src0.txt', 'dest0.txt', noop: true, verbose: true)
      FileUtils.ln_s('src1.txt', 'destdir1', noop: true, verbose: true)
      FileUtils.ln_s('src2.txt', 'dest2.txt', force: true, noop: true, verbose: true)
      FileUtils.ln_s(['srcdir3/src0.txt', 'srcdir3/src1.txt'], 'destdir3', noop: true, verbose: true)

  Output:

      ln -s src0.txt dest0.txt
      ln -s src1.txt destdir1
      ln -sf src2.txt dest2.txt
      ln -s srcdir3/src0.txt srcdir3/src1.txt destdir3

Related: `FileUtils.ln_sf`.

    # File lib/fileutils.rb, line 706
    def ln_s(src, dest, force: nil, relative: false, target_directory: true, noop: nil, verbose: nil)
      if relative
        return ln_sr(src, dest, force: force, noop: noop, verbose: verbose)
      end
      fu_output_message "ln -s#{force ? 'f' : ''} #{[src,dest].flatten.join ' '}" if verbose
      return if noop
      fu_each_src_dest0(src, dest) do |s,d|
        remove_file d, true if force
        File.symlink s, d
      end
    end

Also aliased as: symlink
ln_sf(src, dest, noop: nil, verbose: nil) click to toggle source

Like `FileUtils.ln_s`, but always with keyword argument `force: true` given.

    # File lib/fileutils.rb, line 724
    def ln_sf(src, dest, noop: nil, verbose: nil)
      ln_s src, dest, force: true, noop: noop, verbose: verbose
    end

ln_sr(src, dest, target_directory: true, force: nil, noop: nil, verbose: nil) click to toggle source

Like `FileUtils.ln_s`, but create links relative to `dest`.

    # File lib/fileutils.rb, line 731
    def ln_sr(src, dest, target_directory: true, force: nil, noop: nil, verbose: nil)
      options = "#{force ? 'f' : ''}#{target_directory ? '' : 'T'}"
      dest = File.path(dest)
      srcs = Array(src)
      link = proc do |s, target_dir_p = true|
        s = File.path(s)
        if target_dir_p
          d = File.join(destdirs = dest, File.basename(s))
        else
          destdirs = File.dirname(d = dest)
        end
        destdirs = fu_split_path(File.realpath(destdirs))
        if fu_starting_path?(s)
          srcdirs = fu_split_path((File.realdirpath(s) rescue File.expand_path(s)))
          base = fu_relative_components_from(srcdirs, destdirs)
          s = File.join(*base)
        else
          srcdirs = fu_clean_components(*fu_split_path(s))
          base = fu_relative_components_from(fu_split_path(Dir.pwd), destdirs)
          while srcdirs.first&. == ".." and base.last&.!=("..") and !fu_starting_path?(base.last)
            srcdirs.shift
            base.pop
          end
          s = File.join(*base, *srcdirs)
        end
        fu_output_message "ln -s#{options} #{s} #{d}" if verbose
        next if noop
        remove_file d, true if force
        File.symlink s, d
      end
      case srcs.size
      when 0
      when 1
        link[srcs[0], target_directory && File.directory?(dest)]
      else
        srcs.each(&link)
      end
    end

makedirs(list, mode: nil, noop: nil, verbose: nil)
Alias for: mkdir_p
mkdir(list, mode: nil, noop: nil, verbose: nil) click to toggle source

Creates directories at the paths in the given `list` (a single path or an array of paths); returns `list` if it is an array, `[list]` otherwise.

Argument `list` or its elements should be interpretable as paths.

With no keyword arguments, creates a directory at each `path` in `list` by calling: `Dir.mkdir(path, mode)`; see `Dir.mkdir`:

    FileUtils.mkdir(%w[tmp0 tmp1]) # => ["tmp0", "tmp1"]
    FileUtils.mkdir('tmp4')        # => ["tmp4"]

Keyword arguments:

- `mode: mode` - also calls `File.chmod(mode, path)`; see `File.chmod`.

- `noop: true` - does not create directories.

- `verbose: true` - prints an equivalent command:

      FileUtils.mkdir(%w[tmp0 tmp1], verbose: true)
      FileUtils.mkdir(%w[tmp2 tmp3], mode: 0700, verbose: true)

  Output:

      mkdir tmp0 tmp1
      mkdir -m 700 tmp2 tmp3

Raises an exception if any path points to an existing file or directory, or if for any reason a directory cannot be created.

Related: `FileUtils.mkdir_p`.

    # File lib/fileutils.rb, line 316
    def mkdir(list, mode: nil, noop: nil, verbose: nil)
      list = fu_list(list)
      fu_output_message "mkdir #{mode ? ('-m %03o ' % mode) : ''}#{list.join ' '}" if verbose
      return if noop

      list.each do |dir|
        fu_mkdir dir, mode
      end
    end

mkdir_p(list, mode: nil, noop: nil, verbose: nil) click to toggle source

Creates directories at the paths in the given `list` (a single path or an array of paths), also creating ancestor directories as needed; returns `list` if it is an array, `[list]` otherwise.

Argument `list` or its elements should be interpretable as paths.

With no keyword arguments, creates a directory at each `path` in `list`, along with any needed ancestor directories, by calling: `Dir.mkdir(path, mode)`; see `Dir.mkdir`:

    FileUtils.mkdir_p(%w[tmp0/tmp1 tmp2/tmp3]) # => ["tmp0/tmp1", "tmp2/tmp3"]
    FileUtils.mkdir_p('tmp4/tmp5')             # => ["tmp4/tmp5"]

Keyword arguments:

- `mode: mode` - also calls `File.chmod(mode, path)`; see `File.chmod`.

- `noop: true` - does not create directories.

- `verbose: true` - prints an equivalent command:

      FileUtils.mkdir_p(%w[tmp0 tmp1], verbose: true)
      FileUtils.mkdir_p(%w[tmp2 tmp3], mode: 0700, verbose: true)

  Output:

      mkdir -p tmp0 tmp1
      mkdir -p -m 700 tmp2 tmp3

Raises an exception if for any reason a directory cannot be created.

`FileUtils.mkpath` and `FileUtils.makedirs` are aliases for `FileUtils.mkdir_p`.

Related: `FileUtils.mkdir`.

    # File lib/fileutils.rb, line 365
    def mkdir_p(list, mode: nil, noop: nil, verbose: nil)
      list = fu_list(list)
      fu_output_message "mkdir -p #{mode ? ('-m %03o ' % mode) : ''}#{list.join ' '}" if verbose
      return *list if noop

      list.each do |item|
        path = remove_trailing_slash(item)

        stack = []
        until File.directory?(path) || File.dirname(path) == path
          stack.push path
          path = File.dirname(path)
        end
        stack.reverse_each do |dir|
          begin
            fu_mkdir dir, mode
          rescue SystemCallError
            raise unless File.directory?(dir)
          end
        end
      end

      return *list
    end

Also aliased as: mkpath, makedirs
mkpath(list, mode: nil, noop: nil, verbose: nil)
Alias for: mkdir_p
move(src, dest, force: nil, noop: nil, verbose: nil, secure: nil)
Alias for: mv
mv(src, dest, force: nil, noop: nil, verbose: nil, secure: nil) click to toggle source

Moves entries.

Arguments `src` (a single path or an array of paths) and `dest` (a single path) should be interpretable as paths.

If `src` and `dest` are on different file systems, first copies, then removes `src`.

May cause a local vulnerability if not called with keyword argument `secure: true`; see Avoiding the TOCTTOU Vulnerability.

If `src` is the path to a single file or directory and `dest` does not exist, moves `src` to `dest`:

    tree('src0')
    # => src0
    #    |-- src0.txt
    #    `-- src1.txt
    File.exist?('dest0') # => false
    FileUtils.mv('src0', 'dest0')
    File.exist?('src0')  # => false
    tree('dest0')
    # => dest0
    #    |-- src0.txt
    #    `-- src1.txt

If `src` is an array of paths to files and directories and `dest` is the path to a directory, copies from each path in the array to `dest`:

    File.file?('src1.txt') # => true
    tree('src1')
    # => src1
    #    |-- src.dat
    #    `-- src.txt
    Dir.empty?('dest1')    # => true
    FileUtils.mv(['src1.txt', 'src1'], 'dest1')
    tree('dest1')
    # => dest1
    #    |-- src1
    #    |   |-- src.dat
    #    |   `-- src.txt
    #    `-- src1.txt

Keyword arguments:

- `force: true` - if the move includes removing `src` (that is, if `src` and `dest` are on different file systems), ignores raised exceptions of `StandardError` and its descendants.

- `noop: true` - does not move files.

- `secure: true` - removes `src` securely; see details at `FileUtils.remove_entry_secure`.

- `verbose: true` - prints an equivalent command:

      FileUtils.mv('src0', 'dest0', noop: true, verbose: true)
      FileUtils.mv(['src1.txt', 'src1'], 'dest1', noop: true, verbose: true)

  Output:

      mv src0 dest0
      mv src1.txt src1 dest1

    # File lib/fileutils.rb, line 1157
    def mv(src, dest, force: nil, noop: nil, verbose: nil, secure: nil)
      fu_output_message "mv#{force ? ' -f' : ''} #{[src,dest].flatten.join ' '}" if verbose
      return if noop
      fu_each_src_dest(src, dest) do |s, d|
        destent = Entry_.new(d, nil, true)
        begin
          if destent.exist?
            if destent.directory?
              raise Errno::EEXIST, d
            end
          end
          begin
            File.rename s, d
          rescue Errno::EXDEV,
                 Errno::EPERM # move from unencrypted to encrypted dir (ext4)
            copy_entry s, d, true
            if secure
              remove_entry_secure s, force
            else
              remove_entry s, force
            end
          end
        rescue SystemCallError
          raise unless force
        end
      end
    end

Also aliased as: move
options() click to toggle source

Returns an array of the string keyword names:

    FileUtils.options.take(3) # => ["noop", "verbose", "force"]

    # File lib/fileutils.rb, line 2578
    def self.options
      OPT_TABLE.values.flatten.uniq.map {|sym| sym.to_s }
    end

options_of(mid) click to toggle source

Returns an array of the string keyword name for method `mid`; the argument may be a string or a symbol:

    FileUtils.options_of(:rm) # => ["force", "noop", "verbose"]
    FileUtils.options_of('mv') # => ["force", "noop", "verbose", "secure"]

    # File lib/fileutils.rb, line 2599
    def self.options_of(mid)
      OPT_TABLE[mid.to_s].map {|sym| sym.to_s }
    end

pwd() click to toggle source

Returns a string containing the path to the current directory:

    FileUtils.pwd # => "/rdoc/fileutils"

Related: `FileUtils.cd`.

    # File lib/fileutils.rb, line 197
    def pwd
      Dir.pwd
    end

Also aliased as: getwd
remove(list, force: nil, noop: nil, verbose: nil)
Alias for: rm
remove_dir(path, force = false) click to toggle source

Recursively removes the directory entry given by `path`, which should be the entry for a regular file, a symbolic link, or a directory.

Argument `path` should be interpretable as a path.

Optional argument `force` specifies whether to ignore raised exceptions of `StandardError` and its descendants.

Related: methods for deleting.

    # File lib/fileutils.rb, line 1492
    def remove_dir(path, force = false)
      remove_entry path, force   # FIXME?? check if it is a directory
    end

remove_entry(path, force = false) click to toggle source

Removes the entry given by `path`, which should be the entry for a regular file, a symbolic link, or a directory.

Argument `path` should be interpretable as a path.

Optional argument `force` specifies whether to ignore raised exceptions of `StandardError` and its descendants.

Related: `FileUtils.remove_entry_secure`.

    # File lib/fileutils.rb, line 1449
    def remove_entry(path, force = false)
      Entry_.new(path).postorder_traverse do |ent|
        begin
          ent.remove
        rescue
          raise unless force
        end
      end
    rescue
      raise unless force
    end

remove_entry_secure(path, force = false) click to toggle source

Securely removes the entry given by `path`, which should be the entry for a regular file, a symbolic link, or a directory.

Argument `path` should be interpretable as a path.

Avoids a local vulnerability that can exist in certain circumstances; see Avoiding the TOCTTOU Vulnerability.

Optional argument `force` specifies whether to ignore raised exceptions of `StandardError` and its descendants.

Related: methods for deleting.

    # File lib/fileutils.rb, line 1351
    def remove_entry_secure(path, force = false)
      unless fu_have_symlink?
        remove_entry path, force
        return
      end
      fullpath = File.expand_path(path)
      st = File.lstat(fullpath)
      unless st.directory?
        File.unlink fullpath
        return
      end
      # is a directory.
      parent_st = File.stat(File.dirname(fullpath))
      unless parent_st.world_writable?
        remove_entry path, force
        return
      end
      unless parent_st.sticky?
        raise ArgumentError, "parent directory is world writable, FileUtils#remove_entry_secure does not work; abort: #{path.inspect} (parent directory mode #{'%o' % parent_st.mode})"
      end

      # freeze tree root
      euid = Process.euid
      dot_file = fullpath + "/."
      begin
        File.open(dot_file) {|f|
          unless fu_stat_identical_entry?(st, f.stat)
            # symlink (TOC-to-TOU attack?)
            File.unlink fullpath
            return
          end
          f.chown euid, -1
          f.chmod 0700
        }
      rescue Errno::EISDIR # JRuby in non-native mode can't open files as dirs
        File.lstat(dot_file).tap {|fstat|
          unless fu_stat_identical_entry?(st, fstat)
            # symlink (TOC-to-TOU attack?)
            File.unlink fullpath
            return
          end
          File.chown euid, -1, dot_file
          File.chmod 0700, dot_file
        }
      end

      unless fu_stat_identical_entry?(st, File.lstat(fullpath))
        # TOC-to-TOU attack?
        File.unlink fullpath
        return
      end

      # ---- tree root is frozen ----
      root = Entry_.new(path)
      root.preorder_traverse do |ent|
        if ent.directory?
          ent.chown euid, -1
          ent.chmod 0700
        end
      end
      root.postorder_traverse do |ent|
        begin
          ent.remove
        rescue
          raise unless force
        end
      end
    rescue
      raise unless force
    end

remove_file(path, force = false) click to toggle source

Removes the file entry given by `path`, which should be the entry for a regular file or a symbolic link.

Argument `path` should be interpretable as a path.

Optional argument `force` specifies whether to ignore raised exceptions of `StandardError` and its descendants.

Related: methods for deleting.

    # File lib/fileutils.rb, line 1473
    def remove_file(path, force = false)
      Entry_.new(path).remove_file
    rescue
      raise unless force
    end

rm(list, force: nil, noop: nil, verbose: nil) click to toggle source

Removes entries at the paths in the given `list` (a single path or an array of paths) returns `list`, if it is an array, `[list]` otherwise.

Argument `list` or its elements should be interpretable as paths.

With no keyword arguments, removes files at the paths given in `list`:

    FileUtils.touch(['src0.txt', 'src0.dat'])
    FileUtils.rm(['src0.dat', 'src0.txt']) # => ["src0.dat", "src0.txt"]

Keyword arguments:

- `force: true` - ignores raised exceptions of `StandardError` and its descendants.

- `noop: true` - does not remove files; returns `nil`.

- `verbose: true` - prints an equivalent command:

      FileUtils.rm(['src0.dat', 'src0.txt'], noop: true, verbose: true)

  Output:

      rm src0.dat src0.txt

Related: methods for deleting.

    # File lib/fileutils.rb, line 1216
    def rm(list, force: nil, noop: nil, verbose: nil)
      list = fu_list(list)
      fu_output_message "rm#{force ? ' -f' : ''} #{list.join ' '}" if verbose
      return if noop

      list.each do |path|
        remove_file path, force
      end
    end

Also aliased as: remove
rm_f(list, noop: nil, verbose: nil) click to toggle source

Equivalent to:

    FileUtils.rm(list, force: true, **kwargs)

Argument `list` (a single path or an array of paths) should be interpretable as paths.

See `FileUtils.rm` for keyword arguments.

Related: methods for deleting.

    # File lib/fileutils.rb, line 1241
    def rm_f(list, noop: nil, verbose: nil)
      rm list, force: true, noop: noop, verbose: verbose
    end

Also aliased as: safe_unlink
rm_r(list, force: nil, noop: nil, verbose: nil, secure: nil) click to toggle source

Removes entries at the paths in the given `list` (a single path or an array of paths); returns `list`, if it is an array, `[list]` otherwise.

Argument `list` or its elements should be interpretable as paths.

May cause a local vulnerability if not called with keyword argument `secure: true`; see Avoiding the TOCTTOU Vulnerability.

For each file path, removes the file at that path:

    FileUtils.touch(['src0.txt', 'src0.dat'])
    FileUtils.rm_r(['src0.dat', 'src0.txt'])
    File.exist?('src0.txt') # => false
    File.exist?('src0.dat') # => false

For each directory path, recursively removes files and directories:

    tree('src1')
    # => src1
    #    |-- dir0
    #    |   |-- src0.txt
    #    |   `-- src1.txt
    #    `-- dir1
    #        |-- src2.txt
    #        `-- src3.txt
    FileUtils.rm_r('src1')
    File.exist?('src1') # => false

Keyword arguments:

- `force: true` - ignores raised exceptions of `StandardError` and its descendants.

- `noop: true` - does not remove entries; returns `nil`.

- `secure: true` - removes `src` securely; see details at `FileUtils.remove_entry_secure`.

- `verbose: true` - prints an equivalent command:

      FileUtils.rm_r(['src0.dat', 'src0.txt'], noop: true, verbose: true)
      FileUtils.rm_r('src1', noop: true, verbose: true)

  Output:

      rm -r src0.dat src0.txt
      rm -r src1

Related: methods for deleting.

    # File lib/fileutils.rb, line 1299
    def rm_r(list, force: nil, noop: nil, verbose: nil, secure: nil)
      list = fu_list(list)
      fu_output_message "rm -r#{force ? 'f' : ''} #{list.join ' '}" if verbose
      return if noop
      list.each do |path|
        if secure
          remove_entry_secure path, force
        else
          remove_entry path, force
        end
      end
    end

rm_rf(list, noop: nil, verbose: nil, secure: nil) click to toggle source

Equivalent to:

    FileUtils.rm_r(list, force: true, **kwargs)

Argument `list` or its elements should be interpretable as paths.

May cause a local vulnerability if not called with keyword argument `secure: true`; see Avoiding the TOCTTOU Vulnerability.

See `FileUtils.rm_r` for keyword arguments.

Related: methods for deleting.

    # File lib/fileutils.rb, line 1328
    def rm_rf(list, noop: nil, verbose: nil, secure: nil)
      rm_r list, force: true, noop: noop, verbose: verbose, secure: secure
    end

Also aliased as: rmtree
rmdir(list, parents: nil, noop: nil, verbose: nil) click to toggle source

Removes directories at the paths in the given `list` (a single path or an array of paths); returns `list`, if it is an array, `[list]` otherwise.

Argument `list` or its elements should be interpretable as paths.

With no keyword arguments, removes the directory at each `path` in `list`, by calling: `Dir.rmdir(path)`; see `Dir.rmdir`:

    FileUtils.rmdir(%w[tmp0/tmp1 tmp2/tmp3]) # => ["tmp0/tmp1", "tmp2/tmp3"]
    FileUtils.rmdir('tmp4/tmp5')             # => ["tmp4/tmp5"]

Keyword arguments:

- `parents: true` - removes successive ancestor directories if empty.

- `noop: true` - does not remove directories.

- `verbose: true` - prints an equivalent command:

      FileUtils.rmdir(%w[tmp0/tmp1 tmp2/tmp3], parents: true, verbose: true)
      FileUtils.rmdir('tmp4/tmp5', parents: true, verbose: true)

  Output:

      rmdir -p tmp0/tmp1 tmp2/tmp3
      rmdir -p tmp4/tmp5

Raises an exception if a directory does not exist or if for any reason a directory cannot be removed.

Related: methods for deleting.

    # File lib/fileutils.rb, line 442
    def rmdir(list, parents: nil, noop: nil, verbose: nil)
      list = fu_list(list)
      fu_output_message "rmdir #{parents ? '-p ' : ''}#{list.join ' '}" if verbose
      return if noop
      list.each do |dir|
        Dir.rmdir(dir = remove_trailing_slash(dir))
        if parents
          begin
            until (parent = File.dirname(dir)) == '.' or parent == dir
              dir = parent
              Dir.rmdir(dir)
            end
          rescue Errno::ENOTEMPTY, Errno::EEXIST, Errno::ENOENT
          end
        end
      end
    end

rmtree(list, noop: nil, verbose: nil, secure: nil)
Alias for: rm_rf
safe_unlink(list, noop: nil, verbose: nil)
Alias for: rm_f
symlink(src, dest, force: nil, relative: false, target_directory: true, noop: nil, verbose: nil)
Alias for: ln_s
touch(list, noop: nil, verbose: nil, mtime: nil, nocreate: nil) click to toggle source

Updates modification times (mtime) and access times (atime) of the entries given by the paths in `list` (a single path or an array of paths); returns `list` if it is an array, `[list]` otherwise.

By default, creates an empty file for any path to a non-existent entry; use keyword argument `nocreate` to raise an exception instead.

Argument `list` or its elements should be interpretable as paths.

Examples:

    # Single path.
    f = File.new('src0.txt') # Existing file.
    f.atime # => 2022-06-10 11:11:21.200277 -0700
    f.mtime # => 2022-06-10 11:11:21.200277 -0700
    FileUtils.touch('src0.txt')
    f = File.new('src0.txt')
    f.atime # => 2022-06-11 08:28:09.8185343 -0700
    f.mtime # => 2022-06-11 08:28:09.8185343 -0700

    # Array of paths.
    FileUtils.touch(['src0.txt', 'src0.dat'])

Keyword arguments:

- `mtime: time` - sets the entry’s mtime to the given time, instead of the current time.

- `nocreate: true` - raises an exception if the entry does not exist.

- `noop: true` - does not touch entries; returns `nil`.

- `verbose: true` - prints an equivalent command:

      FileUtils.touch('src0.txt', noop: true, verbose: true)
      FileUtils.touch(['src0.txt', 'src0.dat'], noop: true, verbose: true)
      FileUtils.touch(path, noop: true, verbose: true)

  Output:

      touch src0.txt
      touch src0.txt src0.dat
      touch src0.txt

Related: `FileUtils.uptodate?`.

    # File lib/fileutils.rb, line 2006
    def touch(list, noop: nil, verbose: nil, mtime: nil, nocreate: nil)
      list = fu_list(list)
      t = mtime
      if verbose
        fu_output_message "touch #{nocreate ? '-c ' : ''}#{t ? t.strftime('-t %Y%m%d%H%M.%S ') : ''}#{list.join ' '}"
      end
      return if noop
      list.each do |path|
        created = nocreate
        begin
          File.utime(t, t, path)
        rescue Errno::ENOENT
          raise if created
          File.open(path, 'a') {
            ;
          }
          created = true
          retry if t
        end
      end
    end

uptodate?(new, old_list) click to toggle source

Returns `true` if the file at path `new` is newer than all the files at paths in array `old_list`; `false` otherwise.

Argument `new` and the elements of `old_list` should be interpretable as paths:

    FileUtils.uptodate?('Rakefile', ['Gemfile', 'README.md']) # => true
    FileUtils.uptodate?('Gemfile', ['Rakefile', 'README.md']) # => false

A non-existent file is considered to be infinitely old.

Related: `FileUtils.touch`.

    # File lib/fileutils.rb, line 264
    def uptodate?(new, old_list)
      return false unless File.exist?(new)
      new_time = File.mtime(new)
      old_list.each do |old|
        if File.exist?(old)
          return false unless new_time > File.mtime(old)
        end
      end
      true
    end

### Private Instance Methods

cd(dir, verbose: nil) { |dir| ... } click to toggle source

Changes the working directory to the given `dir`, which should be interpretable as a path:

With no block given, changes the current directory to the directory at `dir`; returns zero:

    FileUtils.pwd # => "/rdoc/fileutils"
    FileUtils.cd('..')
    FileUtils.pwd # => "/rdoc"
    FileUtils.cd('fileutils')

With a block given, changes the current directory to the directory at `dir`, calls the block with argument `dir`, and restores the original current directory; returns the block’s value:

    FileUtils.pwd                                     # => "/rdoc/fileutils"
    FileUtils.cd('..') { |arg| [arg, FileUtils.pwd] } # => ["..", "/rdoc"]
    FileUtils.pwd                                     # => "/rdoc/fileutils"

Keyword arguments:

- `verbose: true` - prints an equivalent command:

      FileUtils.cd('..')
      FileUtils.cd('fileutils')

  Output:

      cd ..
      cd fileutils

Related: `FileUtils.pwd`.

    # File lib/fileutils.rb, line 238
    def cd(dir, verbose: nil, &block) # :yield: dir
      fu_output_message "cd #{dir}" if verbose
      result = Dir.chdir(dir, &block)
      fu_output_message 'cd -' if verbose and block
      result
    end

Also aliased as: chdir
chdir(dir, verbose: nil)
Alias for: cd
chmod(mode, list, noop: nil, verbose: nil) click to toggle source

Changes permissions on the entries at the paths given in `list` (a single path or an array of paths) to the permissions given by `mode`; returns `list` if it is an array, `[list]` otherwise:

- Modifies each entry that is a regular file using `File.chmod`.

- Modifies each entry that is a symbolic link using `File.lchmod`.

Argument `list` or its elements should be interpretable as paths.

Argument `mode` may be either an integer or a string:

- Integer `mode`: represents the permission bits to be set:

      FileUtils.chmod(0755, 'src0.txt')
      FileUtils.chmod(0644, ['src0.txt', 'src0.dat'])

- String `mode`: represents the permissions to be set:

  The string is of the form `[targets][[operator][perms[,perms]]`, where:

  - `targets` may be any combination of these letters:

    - `'u'`: permissions apply to the file’s owner.

    - `'g'`: permissions apply to users in the file’s group.

    - `'o'`: permissions apply to other users not in the file’s group.

    - `'a'` (the default): permissions apply to all users.

  - `operator` may be one of these letters:

    - `'+'`: adds permissions.

    - `'-'`: removes permissions.

    - `'='`: sets (replaces) permissions.

  - `perms` (may be repeated, with separating commas) may be any combination of these letters:

    - `'r'`: Read.

    - `'w'`: Write.

    - `'x'`: Execute (search, for a directory).

    - `'X'`: Search (for a directories only; must be used with `'+'`)

    - `'s'`: Uid or gid.

    - `'t'`: Sticky bit.

  Examples:

      FileUtils.chmod('u=wrx,go=rx', 'src1.txt')
      FileUtils.chmod('u=wrx,go=rx', '/usr/bin/ruby')

Keyword arguments:

- `noop: true` - does not change permissions; returns `nil`.

- `verbose: true` - prints an equivalent command:

      FileUtils.chmod(0755, 'src0.txt', noop: true, verbose: true)
      FileUtils.chmod(0644, ['src0.txt', 'src0.dat'], noop: true, verbose: true)
      FileUtils.chmod('u=wrx,go=rx', 'src1.txt', noop: true, verbose: true)
      FileUtils.chmod('u=wrx,go=rx', '/usr/bin/ruby', noop: true, verbose: true)

  Output:

      chmod 755 src0.txt
      chmod 644 src0.txt src0.dat
      chmod u=wrx,go=rx src1.txt
      chmod u=wrx,go=rx /usr/bin/ruby

Related: `FileUtils.chmod_R`.

    # File lib/fileutils.rb, line 1803
    def chmod(mode, list, noop: nil, verbose: nil)
      list = fu_list(list)
      fu_output_message sprintf('chmod %s %s', mode_to_s(mode), list.join(' ')) if verbose
      return if noop
      list.each do |path|
        Entry_.new(path).chmod(fu_mode(mode, path))
      end
    end

chmod_R(mode, list, noop: nil, verbose: nil, force: nil) click to toggle source

Like `FileUtils.chmod`, but changes permissions recursively.

    # File lib/fileutils.rb, line 1815
    def chmod_R(mode, list, noop: nil, verbose: nil, force: nil)
      list = fu_list(list)
      fu_output_message sprintf('chmod -R%s %s %s',
                                (force ? 'f' : ''),
                                mode_to_s(mode), list.join(' ')) if verbose
      return if noop
      list.each do |root|
        Entry_.new(root).traverse do |ent|
          begin
            ent.chmod(fu_mode(mode, ent.path))
          rescue
            raise unless force
          end
        end
      end
    end

chown(user, group, list, noop: nil, verbose: nil) click to toggle source

Changes the owner and group on the entries at the paths given in `list` (a single path or an array of paths) to the given `user` and `group`; returns `list` if it is an array, `[list]` otherwise:

- Modifies each entry that is a regular file using `File.chown`.

- Modifies each entry that is a symbolic link using `File.lchown`.

Argument `list` or its elements should be interpretable as paths.

User and group:

- Argument `user` may be a user name or a user id; if `nil` or `-1`, the user is not changed.

- Argument `group` may be a group name or a group id; if `nil` or `-1`, the group is not changed.

- The user must be a member of the group.

Examples:

    # One path.
    # User and group as string names.
    File.stat('src0.txt').uid # => 1004
    File.stat('src0.txt').gid # => 1004
    FileUtils.chown('user2', 'group1', 'src0.txt')
    File.stat('src0.txt').uid # => 1006
    File.stat('src0.txt').gid # => 1005

    # User and group as uid and gid.
    FileUtils.chown(1004, 1004, 'src0.txt')
    File.stat('src0.txt').uid # => 1004
    File.stat('src0.txt').gid # => 1004

    # Array of paths.
    FileUtils.chown(1006, 1005, ['src0.txt', 'src0.dat'])

    # Directory (not recursive).
    FileUtils.chown('user2', 'group1', '.')

Keyword arguments:

- `noop: true` - does not change permissions; returns `nil`.

- `verbose: true` - prints an equivalent command:

      FileUtils.chown('user2', 'group1', 'src0.txt', noop: true, verbose: true)
      FileUtils.chown(1004, 1004, 'src0.txt', noop: true, verbose: true)
      FileUtils.chown(1006, 1005, ['src0.txt', 'src0.dat'], noop: true, verbose: true)
      FileUtils.chown('user2', 'group1', path, noop: true, verbose: true)
      FileUtils.chown('user2', 'group1', '.', noop: true, verbose: true)

  Output:

      chown user2:group1 src0.txt
      chown 1004:1004 src0.txt
      chown 1006:1005 src0.txt src0.dat
      chown user2:group1 src0.txt
      chown user2:group1 .

Related: `FileUtils.chown_R`.

    # File lib/fileutils.rb, line 1896
    def chown(user, group, list, noop: nil, verbose: nil)
      list = fu_list(list)
      fu_output_message sprintf('chown %s %s',
                                (group ? "#{user}:#{group}" : user || ':'),
                                list.join(' ')) if verbose
      return if noop
      uid = fu_get_uid(user)
      gid = fu_get_gid(group)
      list.each do |path|
        Entry_.new(path).chown uid, gid
      end
    end

chown_R(user, group, list, noop: nil, verbose: nil, force: nil) click to toggle source

Like `FileUtils.chown`, but changes owner and group recursively.

    # File lib/fileutils.rb, line 1912
    def chown_R(user, group, list, noop: nil, verbose: nil, force: nil)
      list = fu_list(list)
      fu_output_message sprintf('chown -R%s %s %s',
                                (force ? 'f' : ''),
                                (group ? "#{user}:#{group}" : user || ':'),
                                list.join(' ')) if verbose
      return if noop
      uid = fu_get_uid(user)
      gid = fu_get_gid(group)
      list.each do |root|
        Entry_.new(root).traverse do |ent|
          begin
            ent.chown uid, gid
          rescue
            raise unless force
          end
        end
      end
    end

cmp(a, b)
Alias for: compare_file
compare_file(a, b) click to toggle source

Returns `true` if the contents of files `a` and `b` are identical, `false` otherwise.

Arguments `a` and `b` should be interpretable as a path.

`FileUtils.identical?` and `FileUtils.cmp` are aliases for `FileUtils.compare_file`.

Related: `FileUtils.compare_stream`.

    # File lib/fileutils.rb, line 1507
    def compare_file(a, b)
      return false unless File.size(a) == File.size(b)
      File.open(a, 'rb') {|fa|
        File.open(b, 'rb') {|fb|
          return compare_stream(fa, fb)
        }
      }
    end

Also aliased as: identical?, cmp
compare_stream(a, b) click to toggle source

Returns `true` if the contents of streams `a` and `b` are identical, `false` otherwise.

Arguments `a` and `b` should be interpretable as a path.

Related: `FileUtils.compare_file`.

    # File lib/fileutils.rb, line 1530
    def compare_stream(a, b)
      bsize = fu_stream_blksize(a, b)

      sa = String.new(capacity: bsize)
      sb = String.new(capacity: bsize)

      begin
        a.read(bsize, sa)
        b.read(bsize, sb)
        return true if sa.empty? && sb.empty?
      end while sa == sb
      false
    end

copy(src, dest, preserve: nil, noop: nil, verbose: nil)
Alias for: cp
copy_entry(src, dest, preserve = false, dereference_root = false, remove_destination = false) click to toggle source

Recursively copies files from `src` to `dest`.

Arguments `src` and `dest` should be interpretable as paths.

If `src` is the path to a file, copies `src` to `dest`:

    FileUtils.touch('src0.txt')
    File.exist?('dest0.txt') # => false
    FileUtils.copy_entry('src0.txt', 'dest0.txt')
    File.file?('dest0.txt')  # => true

If `src` is a directory, recursively copies `src` to `dest`:

    tree('src1')
    # => src1
    #    |-- dir0
    #    |   |-- src0.txt
    #    |   `-- src1.txt
    #    `-- dir1
    #        |-- src2.txt
    #        `-- src3.txt
    FileUtils.copy_entry('src1', 'dest1')
    tree('dest1')
    # => dest1
    #    |-- dir0
    #    |   |-- src0.txt
    #    |   `-- src1.txt
    #    `-- dir1
    #        |-- src2.txt
    #        `-- src3.txt

The recursive copying preserves file types for regular files, directories, and symbolic links; other file types (FIFO streams, device files, etc.) are not supported.

Keyword arguments:

- `dereference_root: true` - if `src` is a symbolic link, follows the link.

- `preserve: true` - preserves file times.

- `remove_destination: true` - removes `dest` before copying files.

Related: methods for copying.

    # File lib/fileutils.rb, line 1040
    def copy_entry(src, dest, preserve = false, dereference_root = false, remove_destination = false)
      if dereference_root
        src = File.realpath(src)
      end

      Entry_.new(src, nil, false).wrap_traverse(proc do |ent|
        destent = Entry_.new(dest, ent.rel, false)
        File.unlink destent.path if remove_destination && (File.file?(destent.path) || File.symlink?(destent.path))
        ent.copy destent.path
      end, proc do |ent|
        destent = Entry_.new(dest, ent.rel, false)
        ent.copy_metadata destent.path if preserve
      end)
    end

copy_file(src, dest, preserve = false, dereference = true) click to toggle source

Copies file from `src` to `dest`, which should not be directories.

Arguments `src` and `dest` should be interpretable as paths.

Examples:

    FileUtils.touch('src0.txt')
    FileUtils.copy_file('src0.txt', 'dest0.txt')
    File.file?('dest0.txt') # => true

Keyword arguments:

- `dereference: false` - if `src` is a symbolic link, does not follow the link.

- `preserve: true` - preserves file times.

- `remove_destination: true` - removes `dest` before copying files.

Related: methods for copying.

    # File lib/fileutils.rb, line 1076
    def copy_file(src, dest, preserve = false, dereference = true)
      ent = Entry_.new(src, nil, dereference)
      ent.copy_file dest
      ent.copy_metadata dest if preserve
    end

copy_stream(src, dest) click to toggle source

Copies IO stream `src` to IO stream `dest` via `IO.copy_stream`.

Related: methods for copying.

    # File lib/fileutils.rb, line 1088
    def copy_stream(src, dest)
      IO.copy_stream(src, dest)
    end

cp(src, dest, preserve: nil, noop: nil, verbose: nil) click to toggle source

Copies files.

Arguments `src` (a single path or an array of paths) and `dest` (a single path) should be interpretable as paths.

If `src` is the path to a file and `dest` is not the path to a directory, copies `src` to `dest`:

    FileUtils.touch('src0.txt')
    File.exist?('dest0.txt') # => false
    FileUtils.cp('src0.txt', 'dest0.txt')
    File.file?('dest0.txt')  # => true

If `src` is the path to a file and `dest` is the path to a directory, copies `src` to `dest/src`:

    FileUtils.touch('src1.txt')
    FileUtils.mkdir('dest1')
    FileUtils.cp('src1.txt', 'dest1')
    File.file?('dest1/src1.txt') # => true

If `src` is an array of paths to files and `dest` is the path to a directory, copies from each `src` to `dest`:

    src_file_paths = ['src2.txt', 'src2.dat']
    FileUtils.touch(src_file_paths)
    FileUtils.mkdir('dest2')
    FileUtils.cp(src_file_paths, 'dest2')
    File.file?('dest2/src2.txt') # => true
    File.file?('dest2/src2.dat') # => true

Keyword arguments:

- `preserve: true` - preserves file times.

- `noop: true` - does not copy files.

- `verbose: true` - prints an equivalent command:

      FileUtils.cp('src0.txt', 'dest0.txt', noop: true, verbose: true)
      FileUtils.cp('src1.txt', 'dest1', noop: true, verbose: true)
      FileUtils.cp(src_file_paths, 'dest2', noop: true, verbose: true)

  Output:

      cp src0.txt dest0.txt
      cp src1.txt dest1
      cp src2.txt src2.dat dest2

Raises an exception if `src` is a directory.

Related: methods for copying.

    # File lib/fileutils.rb, line 873
    def cp(src, dest, preserve: nil, noop: nil, verbose: nil)
      fu_output_message "cp#{preserve ? ' -p' : ''} #{[src,dest].flatten.join ' '}" if verbose
      return if noop
      fu_each_src_dest(src, dest) do |s, d|
        copy_file s, d, preserve
      end
    end

Also aliased as: copy
cp_lr(src, dest, noop: nil, verbose: nil, dereference_root: true, remove_destination: false) click to toggle source

Creates hard links.

Arguments `src` (a single path or an array of paths) and `dest` (a single path) should be interpretable as paths.

If `src` is the path to a directory and `dest` does not exist, creates links `dest` and descendents pointing to `src` and its descendents:

    tree('src0')
    # => src0
    #    |-- sub0
    #    |   |-- src0.txt
    #    |   `-- src1.txt
    #    `-- sub1
    #        |-- src2.txt
    #        `-- src3.txt
    File.exist?('dest0') # => false
    FileUtils.cp_lr('src0', 'dest0')
    tree('dest0')
    # => dest0
    #    |-- sub0
    #    |   |-- src0.txt
    #    |   `-- src1.txt
    #    `-- sub1
    #        |-- src2.txt
    #        `-- src3.txt

If `src` and `dest` are both paths to directories, creates links `dest/src` and descendents pointing to `src` and its descendents:

    tree('src1')
    # => src1
    #    |-- sub0
    #    |   |-- src0.txt
    #    |   `-- src1.txt
    #    `-- sub1
    #        |-- src2.txt
    #        `-- src3.txt
    FileUtils.mkdir('dest1')
    FileUtils.cp_lr('src1', 'dest1')
    tree('dest1')
    # => dest1
    #    `-- src1
    #        |-- sub0
    #        |   |-- src0.txt
    #        |   `-- src1.txt
    #        `-- sub1
    #            |-- src2.txt
    #            `-- src3.txt

If `src` is an array of paths to entries and `dest` is the path to a directory, for each path `filepath` in `src`, creates a link at `dest/filepath` pointing to that path:

    tree('src2')
    # => src2
    #    |-- sub0
    #    |   |-- src0.txt
    #    |   `-- src1.txt
    #    `-- sub1
    #        |-- src2.txt
    #        `-- src3.txt
    FileUtils.mkdir('dest2')
    FileUtils.cp_lr(['src2/sub0', 'src2/sub1'], 'dest2')
    tree('dest2')
    # => dest2
    #    |-- sub0
    #    |   |-- src0.txt
    #    |   `-- src1.txt
    #    `-- sub1
    #        |-- src2.txt
    #        `-- src3.txt

Keyword arguments:

- `dereference_root: false` - if `src` is a symbolic link, does not dereference it.

- `noop: true` - does not create links.

- `remove_destination: true` - removes `dest` before creating links.

- `verbose: true` - prints an equivalent command:

      FileUtils.cp_lr('src0', 'dest0', noop: true, verbose: true)
      FileUtils.cp_lr('src1', 'dest1', noop: true, verbose: true)
      FileUtils.cp_lr(['src2/sub0', 'src2/sub1'], 'dest2', noop: true, verbose: true)

  Output:

      cp -lr src0 dest0
      cp -lr src1 dest1
      cp -lr src2/sub0 src2/sub1 dest2

Raises an exception if `dest` is the path to an existing file or directory and keyword argument `remove_destination: true` is not given.

Related: methods for copying.

    # File lib/fileutils.rb, line 627
    def cp_lr(src, dest, noop: nil, verbose: nil,
              dereference_root: true, remove_destination: false)
      fu_output_message "cp -lr#{remove_destination ? ' --remove-destination' : ''} #{[src,dest].flatten.join ' '}" if verbose
      return if noop
      fu_each_src_dest(src, dest) do |s, d|
        link_entry s, d, dereference_root, remove_destination
      end
    end

cp_r(src, dest, preserve: nil, noop: nil, verbose: nil, dereference_root: true, remove_destination: nil) click to toggle source

Recursively copies files.

Arguments `src` (a single path or an array of paths) and `dest` (a single path) should be interpretable as paths.

The mode, owner, and group are retained in the copy; to change those, use `FileUtils.install` instead.

If `src` is the path to a file and `dest` is not the path to a directory, copies `src` to `dest`:

    FileUtils.touch('src0.txt')
    File.exist?('dest0.txt') # => false
    FileUtils.cp_r('src0.txt', 'dest0.txt')
    File.file?('dest0.txt')  # => true

If `src` is the path to a file and `dest` is the path to a directory, copies `src` to `dest/src`:

    FileUtils.touch('src1.txt')
    FileUtils.mkdir('dest1')
    FileUtils.cp_r('src1.txt', 'dest1')
    File.file?('dest1/src1.txt') # => true

If `src` is the path to a directory and `dest` does not exist, recursively copies `src` to `dest`:

    tree('src2')
    # => src2
    #    |-- dir0
    #    |   |-- src0.txt
    #    |   `-- src1.txt
    #    `-- dir1
    #    |-- src2.txt
    #    `-- src3.txt
    FileUtils.exist?('dest2') # => false
    FileUtils.cp_r('src2', 'dest2')
    tree('dest2')
    # => dest2
    #    |-- dir0
    #    |   |-- src0.txt
    #    |   `-- src1.txt
    #    `-- dir1
    #    |-- src2.txt
    #    `-- src3.txt

If `src` and `dest` are paths to directories, recursively copies `src` to `dest/src`:

    tree('src3')
    # => src3
    #    |-- dir0
    #    |   |-- src0.txt
    #    |   `-- src1.txt
    #    `-- dir1
    #    |-- src2.txt
    #    `-- src3.txt
    FileUtils.mkdir('dest3')
    FileUtils.cp_r('src3', 'dest3')
    tree('dest3')
    # => dest3
    #    `-- src3
    #      |-- dir0
    #      |   |-- src0.txt
    #      |   `-- src1.txt
    #      `-- dir1
    #          |-- src2.txt
    #          `-- src3.txt

If `src` is an array of paths and `dest` is a directory, recursively copies from each path in `src` to `dest`; the paths in `src` may point to files and/or directories.

Keyword arguments:

- `dereference_root: false` - if `src` is a symbolic link, does not dereference it.

- `noop: true` - does not copy files.

- `preserve: true` - preserves file times.

- `remove_destination: true` - removes `dest` before copying files.

- `verbose: true` - prints an equivalent command:

      FileUtils.cp_r('src0.txt', 'dest0.txt', noop: true, verbose: true)
      FileUtils.cp_r('src1.txt', 'dest1', noop: true, verbose: true)
      FileUtils.cp_r('src2', 'dest2', noop: true, verbose: true)
      FileUtils.cp_r('src3', 'dest3', noop: true, verbose: true)

  Output:

      cp -r src0.txt dest0.txt
      cp -r src1.txt dest1
      cp -r src2 dest2
      cp -r src3 dest3

Raises an exception of `src` is the path to a directory and `dest` is the path to a file.

Related: methods for copying.

    # File lib/fileutils.rb, line 985
    def cp_r(src, dest, preserve: nil, noop: nil, verbose: nil,
             dereference_root: true, remove_destination: nil)
      fu_output_message "cp -r#{preserve ? 'p' : ''}#{remove_destination ? ' --remove-destination' : ''} #{[src,dest].flatten.join ' '}" if verbose
      return if noop
      fu_each_src_dest(src, dest) do |s, d|
        copy_entry s, d, preserve, dereference_root, remove_destination
      end
    end

fu_clean_components(*comp) click to toggle source

    # File lib/fileutils.rb, line 2527
    def fu_clean_components(*comp)
      comp.shift while comp.first == "."
      return comp if comp.empty?
      clean = [comp.shift]
      path = File.join(*clean, "") # ending with File::SEPARATOR
      while c = comp.shift
        if c == ".." and clean.last != ".." and !(fu_have_symlink? && File.symlink?(path))
          clean.pop
          path.chomp!(%r((?<=\A|/)[^/]+/\z), "")
        else
          clean << c
          path << c << "/"
        end
      end
      clean
    end

fu_split_path(path) click to toggle source

    # File lib/fileutils.rb, line 2506
    def fu_split_path(path)
      path = File.path(path)
      list = []
      until (parent, base = File.split(path); parent == path or parent == ".")
        list << base
        path = parent
      end
      list << path
      list.reverse!
    end

fu_starting_path?(path) click to toggle source

    # File lib/fileutils.rb, line 2546
    def fu_starting_path?(path)
      path&.start_with?(%r(\w:|/))
    end

getwd()
Alias for: pwd
identical?(a, b)
Alias for: compare_file
install(src, dest, mode: nil, owner: nil, group: nil, preserve: nil, noop: nil, verbose: nil) click to toggle source

Copies a file entry. See install(1).

Arguments `src` (a single path or an array of paths) and `dest` (a single path) should be interpretable as paths;

If the entry at `dest` does not exist, copies from `src` to `dest`:

    File.read('src0.txt')    # => "aaa\n"
    File.exist?('dest0.txt') # => false
    FileUtils.install('src0.txt', 'dest0.txt')
    File.read('dest0.txt')   # => "aaa\n"

If `dest` is a file entry, copies from `src` to `dest`, overwriting:

    File.read('src1.txt')  # => "aaa\n"
    File.read('dest1.txt') # => "bbb\n"
    FileUtils.install('src1.txt', 'dest1.txt')
    File.read('dest1.txt') # => "aaa\n"

If `dest` is a directory entry, copies from `src` to `dest/src`, overwriting if necessary:

    File.read('src2.txt')       # => "aaa\n"
    File.read('dest2/src2.txt') # => "bbb\n"
    FileUtils.install('src2.txt', 'dest2')
    File.read('dest2/src2.txt') # => "aaa\n"

If `src` is an array of paths and `dest` points to a directory, copies each path `path` in `src` to `dest/path`:

    File.file?('src3.txt') # => true
    File.file?('src3.dat') # => true
    FileUtils.mkdir('dest3')
    FileUtils.install(['src3.txt', 'src3.dat'], 'dest3')
    File.file?('dest3/src3.txt') # => true
    File.file?('dest3/src3.dat') # => true

Keyword arguments:

- `group: group` - changes the group if not `nil`, using `File.chown`.

- `mode: permissions` - changes the permissions. using `File.chmod`.

- `noop: true` - does not copy entries; returns `nil`.

- `owner: owner` - changes the owner if not `nil`, using `File.chown`.

- `preserve: true` - preserve timestamps using `File.utime`.

- `verbose: true` - prints an equivalent command:

      FileUtils.install('src0.txt', 'dest0.txt', noop: true, verbose: true)
      FileUtils.install('src1.txt', 'dest1.txt', noop: true, verbose: true)
      FileUtils.install('src2.txt', 'dest2', noop: true, verbose: true)

  Output:

      install -c src0.txt dest0.txt
      install -c src1.txt dest1.txt
      install -c src2.txt dest2

Related: methods for copying.

    # File lib/fileutils.rb, line 1609
    def install(src, dest, mode: nil, owner: nil, group: nil, preserve: nil,
                noop: nil, verbose: nil)
      if verbose
        msg = +"install -c"
        msg << ' -p' if preserve
        msg << ' -m ' << mode_to_s(mode) if mode
        msg << " -o #{owner}" if owner
        msg << " -g #{group}" if group
        msg << ' ' << [src,dest].flatten.join(' ')
        fu_output_message msg
      end
      return if noop
      uid = fu_get_uid(owner)
      gid = fu_get_gid(group)
      fu_each_src_dest(src, dest) do |s, d|
        st = File.stat(s)
        unless File.exist?(d) and compare_file(s, d)
          remove_file d, true
          if d.end_with?('/')
            mkdir_p d
            copy_file s, d + File.basename(s)
          else
            mkdir_p File.expand_path('..', d)
            copy_file s, d
          end
          File.utime st.atime, st.mtime, d if preserve
          File.chmod fu_mode(mode, st), d if mode
          File.chown uid, gid, d if uid or gid
        end
      end
    end

link(src, dest, force: nil, noop: nil, verbose: nil)
Alias for: ln
link_entry(src, dest, dereference_root = false, remove_destination = false) click to toggle source

Creates hard links; returns `nil`.

Arguments `src` and `dest` should be interpretable as paths.

If `src` is the path to a file and `dest` does not exist, creates a hard link at `dest` pointing to `src`:

    FileUtils.touch('src0.txt')
    File.exist?('dest0.txt') # => false
    FileUtils.link_entry('src0.txt', 'dest0.txt')
    File.file?('dest0.txt')  # => true

If `src` is the path to a directory and `dest` does not exist, recursively creates hard links at `dest` pointing to paths in `src`:

    FileUtils.mkdir_p(['src1/dir0', 'src1/dir1'])
    src_file_paths = [
      'src1/dir0/t0.txt',
      'src1/dir0/t1.txt',
      'src1/dir1/t2.txt',
      'src1/dir1/t3.txt',
      ]
    FileUtils.touch(src_file_paths)
    File.directory?('dest1')        # => true
    FileUtils.link_entry('src1', 'dest1')
    File.file?('dest1/dir0/t0.txt') # => true
    File.file?('dest1/dir0/t1.txt') # => true
    File.file?('dest1/dir1/t2.txt') # => true
    File.file?('dest1/dir1/t3.txt') # => true

Keyword arguments:

- `dereference_root: true` - dereferences `src` if it is a symbolic link.

- `remove_destination: true` - removes `dest` before creating links.

Raises an exception if `dest` is the path to an existing file or directory and keyword argument `remove_destination: true` is not given.

Related: `FileUtils.ln` (has different options).

    # File lib/fileutils.rb, line 812
    def link_entry(src, dest, dereference_root = false, remove_destination = false)
      Entry_.new(src, nil, dereference_root).traverse do |ent|
        destent = Entry_.new(dest, ent.rel, false)
        File.unlink destent.path if remove_destination && File.file?(destent.path)
        ent.link destent.path
      end
    end

ln(src, dest, force: nil, noop: nil, verbose: nil) click to toggle source

Creates hard links.

Arguments `src` (a single path or an array of paths) and `dest` (a single path) should be interpretable as paths.

When `src` is the path to an existing file and `dest` is the path to a non-existent file, creates a hard link at `dest` pointing to `src`; returns zero:

    Dir.children('tmp0/')                    # => ["t.txt"]
    Dir.children('tmp1/')                    # => []
    FileUtils.ln('tmp0/t.txt', 'tmp1/t.lnk') # => 0
    Dir.children('tmp1/')                    # => ["t.lnk"]

When `src` is the path to an existing file and `dest` is the path to an existing directory, creates a hard link at `dest/src` pointing to `src`; returns zero:

    Dir.children('tmp2')               # => ["t.dat"]
    Dir.children('tmp3')               # => []
    FileUtils.ln('tmp2/t.dat', 'tmp3') # => 0
    Dir.children('tmp3')               # => ["t.dat"]

When `src` is an array of paths to existing files and `dest` is the path to an existing directory, then for each path `target` in `src`, creates a hard link at `dest/target` pointing to `target`; returns `src`:

    Dir.children('tmp4/')                               # => []
    FileUtils.ln(['tmp0/t.txt', 'tmp2/t.dat'], 'tmp4/') # => ["tmp0/t.txt", "tmp2/t.dat"]
    Dir.children('tmp4/')                               # => ["t.dat", "t.txt"]

Keyword arguments:

- `force: true` - overwrites `dest` if it exists.

- `noop: true` - does not create links.

- `verbose: true` - prints an equivalent command:

      FileUtils.ln('tmp0/t.txt', 'tmp1/t.lnk', verbose: true)
      FileUtils.ln('tmp2/t.dat', 'tmp3', verbose: true)
      FileUtils.ln(['tmp0/t.txt', 'tmp2/t.dat'], 'tmp4/', verbose: true)

  Output:

      ln tmp0/t.txt tmp1/t.lnk
      ln tmp2/t.dat tmp3
      ln tmp0/t.txt tmp2/t.dat tmp4/

Raises an exception if `dest` is the path to an existing file and keyword argument `force` is not `true`.

Related: `FileUtils.link_entry` (has different options).

    # File lib/fileutils.rb, line 516
    def ln(src, dest, force: nil, noop: nil, verbose: nil)
      fu_output_message "ln#{force ? ' -f' : ''} #{[src,dest].flatten.join ' '}" if verbose
      return if noop
      fu_each_src_dest0(src, dest) do |s,d|
        remove_file d, true if force
        File.link s, d
      end
    end

Also aliased as: link
ln_s(src, dest, force: nil, relative: false, target_directory: true, noop: nil, verbose: nil) click to toggle source

Creates symbolic links.

Arguments `src` (a single path or an array of paths) and `dest` (a single path) should be interpretable as paths.

If `src` is the path to an existing file:

- When `dest` is the path to a non-existent file, creates a symbolic link at `dest` pointing to `src`:

      FileUtils.touch('src0.txt')
      File.exist?('dest0.txt')   # => false
      FileUtils.ln_s('src0.txt', 'dest0.txt')
      File.symlink?('dest0.txt') # => true

- When `dest` is the path to an existing file, creates a symbolic link at `dest` pointing to `src` if and only if keyword argument `force: true` is given (raises an exception otherwise):

      FileUtils.touch('src1.txt')
      FileUtils.touch('dest1.txt')
      FileUtils.ln_s('src1.txt', 'dest1.txt', force: true)
      FileTest.symlink?('dest1.txt') # => true

      FileUtils.ln_s('src1.txt', 'dest1.txt') # Raises Errno::EEXIST.

If `dest` is the path to a directory, creates a symbolic link at `dest/src` pointing to `src`:

    FileUtils.touch('src2.txt')
    FileUtils.mkdir('destdir2')
    FileUtils.ln_s('src2.txt', 'destdir2')
    File.symlink?('destdir2/src2.txt') # => true

If `src` is an array of paths to existing files and `dest` is a directory, for each child `child` in `src` creates a symbolic link `dest/child` pointing to `child`:

    FileUtils.mkdir('srcdir3')
    FileUtils.touch('srcdir3/src0.txt')
    FileUtils.touch('srcdir3/src1.txt')
    FileUtils.mkdir('destdir3')
    FileUtils.ln_s(['srcdir3/src0.txt', 'srcdir3/src1.txt'], 'destdir3')
    File.symlink?('destdir3/src0.txt') # => true
    File.symlink?('destdir3/src1.txt') # => true

Keyword arguments:

- `force: true` - overwrites `dest` if it exists.

- `relative: false` - create links relative to `dest`.

- `noop: true` - does not create links.

- `verbose: true` - prints an equivalent command:

      FileUtils.ln_s('src0.txt', 'dest0.txt', noop: true, verbose: true)
      FileUtils.ln_s('src1.txt', 'destdir1', noop: true, verbose: true)
      FileUtils.ln_s('src2.txt', 'dest2.txt', force: true, noop: true, verbose: true)
      FileUtils.ln_s(['srcdir3/src0.txt', 'srcdir3/src1.txt'], 'destdir3', noop: true, verbose: true)

  Output:

      ln -s src0.txt dest0.txt
      ln -s src1.txt destdir1
      ln -sf src2.txt dest2.txt
      ln -s srcdir3/src0.txt srcdir3/src1.txt destdir3

Related: `FileUtils.ln_sf`.

    # File lib/fileutils.rb, line 706
    def ln_s(src, dest, force: nil, relative: false, target_directory: true, noop: nil, verbose: nil)
      if relative
        return ln_sr(src, dest, force: force, noop: noop, verbose: verbose)
      end
      fu_output_message "ln -s#{force ? 'f' : ''} #{[src,dest].flatten.join ' '}" if verbose
      return if noop
      fu_each_src_dest0(src, dest) do |s,d|
        remove_file d, true if force
        File.symlink s, d
      end
    end

Also aliased as: symlink
ln_sf(src, dest, noop: nil, verbose: nil) click to toggle source

Like `FileUtils.ln_s`, but always with keyword argument `force: true` given.

    # File lib/fileutils.rb, line 724
    def ln_sf(src, dest, noop: nil, verbose: nil)
      ln_s src, dest, force: true, noop: noop, verbose: verbose
    end

ln_sr(src, dest, target_directory: true, force: nil, noop: nil, verbose: nil) click to toggle source

Like `FileUtils.ln_s`, but create links relative to `dest`.

    # File lib/fileutils.rb, line 731
    def ln_sr(src, dest, target_directory: true, force: nil, noop: nil, verbose: nil)
      options = "#{force ? 'f' : ''}#{target_directory ? '' : 'T'}"
      dest = File.path(dest)
      srcs = Array(src)
      link = proc do |s, target_dir_p = true|
        s = File.path(s)
        if target_dir_p
          d = File.join(destdirs = dest, File.basename(s))
        else
          destdirs = File.dirname(d = dest)
        end
        destdirs = fu_split_path(File.realpath(destdirs))
        if fu_starting_path?(s)
          srcdirs = fu_split_path((File.realdirpath(s) rescue File.expand_path(s)))
          base = fu_relative_components_from(srcdirs, destdirs)
          s = File.join(*base)
        else
          srcdirs = fu_clean_components(*fu_split_path(s))
          base = fu_relative_components_from(fu_split_path(Dir.pwd), destdirs)
          while srcdirs.first&. == ".." and base.last&.!=("..") and !fu_starting_path?(base.last)
            srcdirs.shift
            base.pop
          end
          s = File.join(*base, *srcdirs)
        end
        fu_output_message "ln -s#{options} #{s} #{d}" if verbose
        next if noop
        remove_file d, true if force
        File.symlink s, d
      end
      case srcs.size
      when 0
      when 1
        link[srcs[0], target_directory && File.directory?(dest)]
      else
        srcs.each(&link)
      end
    end

makedirs(list, mode: nil, noop: nil, verbose: nil)
Alias for: mkdir_p
mkdir(list, mode: nil, noop: nil, verbose: nil) click to toggle source

Creates directories at the paths in the given `list` (a single path or an array of paths); returns `list` if it is an array, `[list]` otherwise.

Argument `list` or its elements should be interpretable as paths.

With no keyword arguments, creates a directory at each `path` in `list` by calling: `Dir.mkdir(path, mode)`; see `Dir.mkdir`:

    FileUtils.mkdir(%w[tmp0 tmp1]) # => ["tmp0", "tmp1"]
    FileUtils.mkdir('tmp4')        # => ["tmp4"]

Keyword arguments:

- `mode: mode` - also calls `File.chmod(mode, path)`; see `File.chmod`.

- `noop: true` - does not create directories.

- `verbose: true` - prints an equivalent command:

      FileUtils.mkdir(%w[tmp0 tmp1], verbose: true)
      FileUtils.mkdir(%w[tmp2 tmp3], mode: 0700, verbose: true)

  Output:

      mkdir tmp0 tmp1
      mkdir -m 700 tmp2 tmp3

Raises an exception if any path points to an existing file or directory, or if for any reason a directory cannot be created.

Related: `FileUtils.mkdir_p`.

    # File lib/fileutils.rb, line 316
    def mkdir(list, mode: nil, noop: nil, verbose: nil)
      list = fu_list(list)
      fu_output_message "mkdir #{mode ? ('-m %03o ' % mode) : ''}#{list.join ' '}" if verbose
      return if noop

      list.each do |dir|
        fu_mkdir dir, mode
      end
    end

mkdir_p(list, mode: nil, noop: nil, verbose: nil) click to toggle source

Creates directories at the paths in the given `list` (a single path or an array of paths), also creating ancestor directories as needed; returns `list` if it is an array, `[list]` otherwise.

Argument `list` or its elements should be interpretable as paths.

With no keyword arguments, creates a directory at each `path` in `list`, along with any needed ancestor directories, by calling: `Dir.mkdir(path, mode)`; see `Dir.mkdir`:

    FileUtils.mkdir_p(%w[tmp0/tmp1 tmp2/tmp3]) # => ["tmp0/tmp1", "tmp2/tmp3"]
    FileUtils.mkdir_p('tmp4/tmp5')             # => ["tmp4/tmp5"]

Keyword arguments:

- `mode: mode` - also calls `File.chmod(mode, path)`; see `File.chmod`.

- `noop: true` - does not create directories.

- `verbose: true` - prints an equivalent command:

      FileUtils.mkdir_p(%w[tmp0 tmp1], verbose: true)
      FileUtils.mkdir_p(%w[tmp2 tmp3], mode: 0700, verbose: true)

  Output:

      mkdir -p tmp0 tmp1
      mkdir -p -m 700 tmp2 tmp3

Raises an exception if for any reason a directory cannot be created.

`FileUtils.mkpath` and `FileUtils.makedirs` are aliases for `FileUtils.mkdir_p`.

Related: `FileUtils.mkdir`.

    # File lib/fileutils.rb, line 365
    def mkdir_p(list, mode: nil, noop: nil, verbose: nil)
      list = fu_list(list)
      fu_output_message "mkdir -p #{mode ? ('-m %03o ' % mode) : ''}#{list.join ' '}" if verbose
      return *list if noop

      list.each do |item|
        path = remove_trailing_slash(item)

        stack = []
        until File.directory?(path) || File.dirname(path) == path
          stack.push path
          path = File.dirname(path)
        end
        stack.reverse_each do |dir|
          begin
            fu_mkdir dir, mode
          rescue SystemCallError
            raise unless File.directory?(dir)
          end
        end
      end

      return *list
    end

Also aliased as: mkpath, makedirs
mkpath(list, mode: nil, noop: nil, verbose: nil)
Alias for: mkdir_p
move(src, dest, force: nil, noop: nil, verbose: nil, secure: nil)
Alias for: mv
mv(src, dest, force: nil, noop: nil, verbose: nil, secure: nil) click to toggle source

Moves entries.

Arguments `src` (a single path or an array of paths) and `dest` (a single path) should be interpretable as paths.

If `src` and `dest` are on different file systems, first copies, then removes `src`.

May cause a local vulnerability if not called with keyword argument `secure: true`; see Avoiding the TOCTTOU Vulnerability.

If `src` is the path to a single file or directory and `dest` does not exist, moves `src` to `dest`:

    tree('src0')
    # => src0
    #    |-- src0.txt
    #    `-- src1.txt
    File.exist?('dest0') # => false
    FileUtils.mv('src0', 'dest0')
    File.exist?('src0')  # => false
    tree('dest0')
    # => dest0
    #    |-- src0.txt
    #    `-- src1.txt

If `src` is an array of paths to files and directories and `dest` is the path to a directory, copies from each path in the array to `dest`:

    File.file?('src1.txt') # => true
    tree('src1')
    # => src1
    #    |-- src.dat
    #    `-- src.txt
    Dir.empty?('dest1')    # => true
    FileUtils.mv(['src1.txt', 'src1'], 'dest1')
    tree('dest1')
    # => dest1
    #    |-- src1
    #    |   |-- src.dat
    #    |   `-- src.txt
    #    `-- src1.txt

Keyword arguments:

- `force: true` - if the move includes removing `src` (that is, if `src` and `dest` are on different file systems), ignores raised exceptions of `StandardError` and its descendants.

- `noop: true` - does not move files.

- `secure: true` - removes `src` securely; see details at `FileUtils.remove_entry_secure`.

- `verbose: true` - prints an equivalent command:

      FileUtils.mv('src0', 'dest0', noop: true, verbose: true)
      FileUtils.mv(['src1.txt', 'src1'], 'dest1', noop: true, verbose: true)

  Output:

      mv src0 dest0
      mv src1.txt src1 dest1

    # File lib/fileutils.rb, line 1157
    def mv(src, dest, force: nil, noop: nil, verbose: nil, secure: nil)
      fu_output_message "mv#{force ? ' -f' : ''} #{[src,dest].flatten.join ' '}" if verbose
      return if noop
      fu_each_src_dest(src, dest) do |s, d|
        destent = Entry_.new(d, nil, true)
        begin
          if destent.exist?
            if destent.directory?
              raise Errno::EEXIST, d
            end
          end
          begin
            File.rename s, d
          rescue Errno::EXDEV,
                 Errno::EPERM # move from unencrypted to encrypted dir (ext4)
            copy_entry s, d, true
            if secure
              remove_entry_secure s, force
            else
              remove_entry s, force
            end
          end
        rescue SystemCallError
          raise unless force
        end
      end
    end

Also aliased as: move
pwd() click to toggle source

Returns a string containing the path to the current directory:

    FileUtils.pwd # => "/rdoc/fileutils"

Related: `FileUtils.cd`.

    # File lib/fileutils.rb, line 197
    def pwd
      Dir.pwd
    end

Also aliased as: getwd
remove(list, force: nil, noop: nil, verbose: nil)
Alias for: rm
remove_dir(path, force = false) click to toggle source

Recursively removes the directory entry given by `path`, which should be the entry for a regular file, a symbolic link, or a directory.

Argument `path` should be interpretable as a path.

Optional argument `force` specifies whether to ignore raised exceptions of `StandardError` and its descendants.

Related: methods for deleting.

    # File lib/fileutils.rb, line 1492
    def remove_dir(path, force = false)
      remove_entry path, force   # FIXME?? check if it is a directory
    end

remove_entry(path, force = false) click to toggle source

Removes the entry given by `path`, which should be the entry for a regular file, a symbolic link, or a directory.

Argument `path` should be interpretable as a path.

Optional argument `force` specifies whether to ignore raised exceptions of `StandardError` and its descendants.

Related: `FileUtils.remove_entry_secure`.

    # File lib/fileutils.rb, line 1449
    def remove_entry(path, force = false)
      Entry_.new(path).postorder_traverse do |ent|
        begin
          ent.remove
        rescue
          raise unless force
        end
      end
    rescue
      raise unless force
    end

remove_entry_secure(path, force = false) click to toggle source

Securely removes the entry given by `path`, which should be the entry for a regular file, a symbolic link, or a directory.

Argument `path` should be interpretable as a path.

Avoids a local vulnerability that can exist in certain circumstances; see Avoiding the TOCTTOU Vulnerability.

Optional argument `force` specifies whether to ignore raised exceptions of `StandardError` and its descendants.

Related: methods for deleting.

    # File lib/fileutils.rb, line 1351
    def remove_entry_secure(path, force = false)
      unless fu_have_symlink?
        remove_entry path, force
        return
      end
      fullpath = File.expand_path(path)
      st = File.lstat(fullpath)
      unless st.directory?
        File.unlink fullpath
        return
      end
      # is a directory.
      parent_st = File.stat(File.dirname(fullpath))
      unless parent_st.world_writable?
        remove_entry path, force
        return
      end
      unless parent_st.sticky?
        raise ArgumentError, "parent directory is world writable, FileUtils#remove_entry_secure does not work; abort: #{path.inspect} (parent directory mode #{'%o' % parent_st.mode})"
      end

      # freeze tree root
      euid = Process.euid
      dot_file = fullpath + "/."
      begin
        File.open(dot_file) {|f|
          unless fu_stat_identical_entry?(st, f.stat)
            # symlink (TOC-to-TOU attack?)
            File.unlink fullpath
            return
          end
          f.chown euid, -1
          f.chmod 0700
        }
      rescue Errno::EISDIR # JRuby in non-native mode can't open files as dirs
        File.lstat(dot_file).tap {|fstat|
          unless fu_stat_identical_entry?(st, fstat)
            # symlink (TOC-to-TOU attack?)
            File.unlink fullpath
            return
          end
          File.chown euid, -1, dot_file
          File.chmod 0700, dot_file
        }
      end

      unless fu_stat_identical_entry?(st, File.lstat(fullpath))
        # TOC-to-TOU attack?
        File.unlink fullpath
        return
      end

      # ---- tree root is frozen ----
      root = Entry_.new(path)
      root.preorder_traverse do |ent|
        if ent.directory?
          ent.chown euid, -1
          ent.chmod 0700
        end
      end
      root.postorder_traverse do |ent|
        begin
          ent.remove
        rescue
          raise unless force
        end
      end
    rescue
      raise unless force
    end

remove_file(path, force = false) click to toggle source

Removes the file entry given by `path`, which should be the entry for a regular file or a symbolic link.

Argument `path` should be interpretable as a path.

Optional argument `force` specifies whether to ignore raised exceptions of `StandardError` and its descendants.

Related: methods for deleting.

    # File lib/fileutils.rb, line 1473
    def remove_file(path, force = false)
      Entry_.new(path).remove_file
    rescue
      raise unless force
    end

rm(list, force: nil, noop: nil, verbose: nil) click to toggle source

Removes entries at the paths in the given `list` (a single path or an array of paths) returns `list`, if it is an array, `[list]` otherwise.

Argument `list` or its elements should be interpretable as paths.

With no keyword arguments, removes files at the paths given in `list`:

    FileUtils.touch(['src0.txt', 'src0.dat'])
    FileUtils.rm(['src0.dat', 'src0.txt']) # => ["src0.dat", "src0.txt"]

Keyword arguments:

- `force: true` - ignores raised exceptions of `StandardError` and its descendants.

- `noop: true` - does not remove files; returns `nil`.

- `verbose: true` - prints an equivalent command:

      FileUtils.rm(['src0.dat', 'src0.txt'], noop: true, verbose: true)

  Output:

      rm src0.dat src0.txt

Related: methods for deleting.

    # File lib/fileutils.rb, line 1216
    def rm(list, force: nil, noop: nil, verbose: nil)
      list = fu_list(list)
      fu_output_message "rm#{force ? ' -f' : ''} #{list.join ' '}" if verbose
      return if noop

      list.each do |path|
        remove_file path, force
      end
    end

Also aliased as: remove
rm_f(list, noop: nil, verbose: nil) click to toggle source

Equivalent to:

    FileUtils.rm(list, force: true, **kwargs)

Argument `list` (a single path or an array of paths) should be interpretable as paths.

See `FileUtils.rm` for keyword arguments.

Related: methods for deleting.

    # File lib/fileutils.rb, line 1241
    def rm_f(list, noop: nil, verbose: nil)
      rm list, force: true, noop: noop, verbose: verbose
    end

Also aliased as: safe_unlink
rm_r(list, force: nil, noop: nil, verbose: nil, secure: nil) click to toggle source

Removes entries at the paths in the given `list` (a single path or an array of paths); returns `list`, if it is an array, `[list]` otherwise.

Argument `list` or its elements should be interpretable as paths.

May cause a local vulnerability if not called with keyword argument `secure: true`; see Avoiding the TOCTTOU Vulnerability.

For each file path, removes the file at that path:

    FileUtils.touch(['src0.txt', 'src0.dat'])
    FileUtils.rm_r(['src0.dat', 'src0.txt'])
    File.exist?('src0.txt') # => false
    File.exist?('src0.dat') # => false

For each directory path, recursively removes files and directories:

    tree('src1')
    # => src1
    #    |-- dir0
    #    |   |-- src0.txt
    #    |   `-- src1.txt
    #    `-- dir1
    #        |-- src2.txt
    #        `-- src3.txt
    FileUtils.rm_r('src1')
    File.exist?('src1') # => false

Keyword arguments:

- `force: true` - ignores raised exceptions of `StandardError` and its descendants.

- `noop: true` - does not remove entries; returns `nil`.

- `secure: true` - removes `src` securely; see details at `FileUtils.remove_entry_secure`.

- `verbose: true` - prints an equivalent command:

      FileUtils.rm_r(['src0.dat', 'src0.txt'], noop: true, verbose: true)
      FileUtils.rm_r('src1', noop: true, verbose: true)

  Output:

      rm -r src0.dat src0.txt
      rm -r src1

Related: methods for deleting.

    # File lib/fileutils.rb, line 1299
    def rm_r(list, force: nil, noop: nil, verbose: nil, secure: nil)
      list = fu_list(list)
      fu_output_message "rm -r#{force ? 'f' : ''} #{list.join ' '}" if verbose
      return if noop
      list.each do |path|
        if secure
          remove_entry_secure path, force
        else
          remove_entry path, force
        end
      end
    end

rm_rf(list, noop: nil, verbose: nil, secure: nil) click to toggle source

Equivalent to:

    FileUtils.rm_r(list, force: true, **kwargs)

Argument `list` or its elements should be interpretable as paths.

May cause a local vulnerability if not called with keyword argument `secure: true`; see Avoiding the TOCTTOU Vulnerability.

See `FileUtils.rm_r` for keyword arguments.

Related: methods for deleting.

    # File lib/fileutils.rb, line 1328
    def rm_rf(list, noop: nil, verbose: nil, secure: nil)
      rm_r list, force: true, noop: noop, verbose: verbose, secure: secure
    end

Also aliased as: rmtree
rmdir(list, parents: nil, noop: nil, verbose: nil) click to toggle source

Removes directories at the paths in the given `list` (a single path or an array of paths); returns `list`, if it is an array, `[list]` otherwise.

Argument `list` or its elements should be interpretable as paths.

With no keyword arguments, removes the directory at each `path` in `list`, by calling: `Dir.rmdir(path)`; see `Dir.rmdir`:

    FileUtils.rmdir(%w[tmp0/tmp1 tmp2/tmp3]) # => ["tmp0/tmp1", "tmp2/tmp3"]
    FileUtils.rmdir('tmp4/tmp5')             # => ["tmp4/tmp5"]

Keyword arguments:

- `parents: true` - removes successive ancestor directories if empty.

- `noop: true` - does not remove directories.

- `verbose: true` - prints an equivalent command:

      FileUtils.rmdir(%w[tmp0/tmp1 tmp2/tmp3], parents: true, verbose: true)
      FileUtils.rmdir('tmp4/tmp5', parents: true, verbose: true)

  Output:

      rmdir -p tmp0/tmp1 tmp2/tmp3
      rmdir -p tmp4/tmp5

Raises an exception if a directory does not exist or if for any reason a directory cannot be removed.

Related: methods for deleting.

    # File lib/fileutils.rb, line 442
    def rmdir(list, parents: nil, noop: nil, verbose: nil)
      list = fu_list(list)
      fu_output_message "rmdir #{parents ? '-p ' : ''}#{list.join ' '}" if verbose
      return if noop
      list.each do |dir|
        Dir.rmdir(dir = remove_trailing_slash(dir))
        if parents
          begin
            until (parent = File.dirname(dir)) == '.' or parent == dir
              dir = parent
              Dir.rmdir(dir)
            end
          rescue Errno::ENOTEMPTY, Errno::EEXIST, Errno::ENOENT
          end
        end
      end
    end

rmtree(list, noop: nil, verbose: nil, secure: nil)
Alias for: rm_rf
safe_unlink(list, noop: nil, verbose: nil)
Alias for: rm_f
symlink(src, dest, force: nil, relative: false, target_directory: true, noop: nil, verbose: nil)
Alias for: ln_s
touch(list, noop: nil, verbose: nil, mtime: nil, nocreate: nil) click to toggle source

Updates modification times (mtime) and access times (atime) of the entries given by the paths in `list` (a single path or an array of paths); returns `list` if it is an array, `[list]` otherwise.

By default, creates an empty file for any path to a non-existent entry; use keyword argument `nocreate` to raise an exception instead.

Argument `list` or its elements should be interpretable as paths.

Examples:

    # Single path.
    f = File.new('src0.txt') # Existing file.
    f.atime # => 2022-06-10 11:11:21.200277 -0700
    f.mtime # => 2022-06-10 11:11:21.200277 -0700
    FileUtils.touch('src0.txt')
    f = File.new('src0.txt')
    f.atime # => 2022-06-11 08:28:09.8185343 -0700
    f.mtime # => 2022-06-11 08:28:09.8185343 -0700

    # Array of paths.
    FileUtils.touch(['src0.txt', 'src0.dat'])

Keyword arguments:

- `mtime: time` - sets the entry’s mtime to the given time, instead of the current time.

- `nocreate: true` - raises an exception if the entry does not exist.

- `noop: true` - does not touch entries; returns `nil`.

- `verbose: true` - prints an equivalent command:

      FileUtils.touch('src0.txt', noop: true, verbose: true)
      FileUtils.touch(['src0.txt', 'src0.dat'], noop: true, verbose: true)
      FileUtils.touch(path, noop: true, verbose: true)

  Output:

      touch src0.txt
      touch src0.txt src0.dat
      touch src0.txt

Related: `FileUtils.uptodate?`.

    # File lib/fileutils.rb, line 2006
    def touch(list, noop: nil, verbose: nil, mtime: nil, nocreate: nil)
      list = fu_list(list)
      t = mtime
      if verbose
        fu_output_message "touch #{nocreate ? '-c ' : ''}#{t ? t.strftime('-t %Y%m%d%H%M.%S ') : ''}#{list.join ' '}"
      end
      return if noop
      list.each do |path|
        created = nocreate
        begin
          File.utime(t, t, path)
        rescue Errno::ENOENT
          raise if created
          File.open(path, 'a') {
            ;
          }
          created = true
          retry if t
        end
      end
    end

uptodate?(new, old_list) click to toggle source

Returns `true` if the file at path `new` is newer than all the files at paths in array `old_list`; `false` otherwise.

Argument `new` and the elements of `old_list` should be interpretable as paths:

    FileUtils.uptodate?('Rakefile', ['Gemfile', 'README.md']) # => true
    FileUtils.uptodate?('Gemfile', ['Rakefile', 'README.md']) # => false

A non-existent file is considered to be infinitely old.

Related: `FileUtils.touch`.

    # File lib/fileutils.rb, line 264
    def uptodate?(new, old_list)
      return false unless File.exist?(new)
      new_time = File.mtime(new)
      old_list.each do |old|
        if File.exist?(old)
          return false unless new_time > File.mtime(old)
        end
      end
      true
    end