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

  • ::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

Copying

Moving

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:

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

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):

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:

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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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_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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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
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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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_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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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
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 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 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