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¶ ↑
-
::mkdir
: Creates directories. -
::mkdir_p
,::makedirs
,::mkpath
: Creates directories, also creating ancestor directories as needed. -
::link_entry
: Creates a hard link. -
::ln_sf
: Creates symbolic links, overwriting if necessary. -
::ln_sr
: Creates symbolic links relative to targets
Deleting¶ ↑
-
::remove_dir
: Removes a directory and its descendants. -
::remove_entry
: Removes an entry, including its descendants if it is a directory. -
::remove_entry_secure
: Like::remove_entry
, but removes securely. -
::remove_file
: Removes a file entry. -
::rm_f
,::safe_unlink
: Like::rm
, but removes forcibly. -
::rm_r
: Removes entries and their descendants. -
::rmdir
: Removes directories.
Querying¶ ↑
-
::uptodate?
: Returns whether a given entry is newer than given other entries.
Setting¶ ↑
-
::chmod
: Sets permissions for an entry. -
::chmod_R
: Sets permissions for an entry and its descendants. -
::chown
: Sets the owner and group for entries. -
::chown_R
: Sets the owner and group for entries and their descendants. -
::touch
: Sets modification and access times for entries, creating if necessary.
Comparing¶ ↑
-
::compare_file
,::cmp
,::identical?
: Returns whether two entries are identical. -
::compare_stream
: Returns whether two streams are identical.
Copying¶ ↑
-
::copy_entry
: Recursively copies an entry. -
::copy_file
: Copies an entry. -
::copy_stream
: Copies a stream. -
::cp_lr
: Recursively creates hard links. -
::cp_r
: Recursively copies files, retaining mode, owner, and group. -
::install
: Recursively copies files, optionally setting mode, owner, and group.
Moving¶ ↑
Options¶ ↑
-
::collect_method
: Returns the names of methods that accept a given option. -
::commands
: Returns the names of methods that accept options. -
::have_option?
: Returns whether a given method accepts a given option. -
::options
: Returns all option names. -
::options_of
: Returns the names of the options for a given method.
Path Arguments¶ ↑
Some methods in FileUtils accept path arguments, which are interpreted as paths to filesystem entries:
-
If the argument is a string, that value is the path.
-
If the argument has method
:to_path
, it is converted via that method. -
If the argument has method
:to_str
, it is converted via that method.
About the Examples¶ ↑
Some examples here involve trees of file entries. For these, we sometimes display trees using the tree command-line utility, which is a recursive directory-listing utility that produces a depth-indented listing of files and directories.
We use a helper method to launch the command and control the format:
def tree(dirpath = '.') command = "tree --noreport --charset=ascii #{dirpath}" system(command) end
To illustrate:
tree('src0') # => src0 # |-- sub0 # | |-- src0.txt # | `-- src1.txt # `-- sub1 # |-- src2.txt # `-- src3.txt
Avoiding the TOCTTOU Vulnerability¶ ↑
For certain methods that recursively remove entries, there is a potential vulnerability called the Time-of-check to time-of-use, or TOCTTOU, vulnerability that can exist when:
-
An ancestor directory of the entry at the target path is world writable; such directories include
/tmp
. -
The directory tree at the target path includes:
-
A world-writable descendant directory.
-
A symbolic link.
-
To avoid that vulnerability, you can use this method to remove entries:
-
FileUtils.remove_entry_secure
: removes recursively if the target path points to a directory.
Also available are these methods, each of which calls FileUtils.remove_entry_secure:
-
FileUtils.rm_r
with keyword argumentsecure: true
. -
FileUtils.rm_rf
with keyword argumentsecure: true
.
Finally, this method for moving entries calls FileUtils.remove_entry_secure if the source and destination are on different file systems (which means that the “move” is really a copy and remove):
-
FileUtils.mv
with keyword argumentsecure: true
.
Method FileUtils.remove_entry_secure removes securely by applying a special pre-process:
-
If the target path points to a directory, this method uses methods File#chown and File#chmod in removing directories.
-
The owner of the target directory should be either the current process or the super user (root).
WARNING: You must ensure that ALL parent directories cannot be moved by other untrusted users. For example, parent directories should not be owned by untrusted users, and should not be world writable except when the sticky bit is set.
For details of this security vulnerability, see Perl cases:
Constants
- VERSION
Public Class Methods
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
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; returnsnil
. -
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
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
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; ifnil
or-1
, the user is not changed. -
Argument
group
may be a group name or a group id; ifnil
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; returnsnil
. -
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
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
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
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
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
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
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
- ifsrc
is a symbolic link, follows the link. -
preserve: true
- preserves file times. -
remove_destination: true
- removesdest
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
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
- ifsrc
is a symbolic link, does not follow the link. -
preserve: true
- preserves file times. -
remove_destination: true
- removesdest
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
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
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
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
- ifsrc
is a symbolic link, does not dereference it. -
noop: true
- does not create links. -
remove_destination: true
- removesdest
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
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
- ifsrc
is a symbolic link, does not dereference it. -
noop: true
- does not copy files. -
preserve: true
- preserves file times. -
remove_destination: true
- removesdest
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
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
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 notnil
, using File.chown. -
mode: permissions
- changes the permissions. using File.chmod. -
noop: true
- does not copy entries; returnsnil
. -
owner: owner
- changes the owner if notnil
, 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
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
- dereferencessrc
if it is a symbolic link. -
remove_destination: true
- removesdest
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
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
- overwritesdest
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
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 atdest
pointing tosrc
: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 atdest
pointing tosrc
if and only if keyword argumentforce: 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
- overwritesdest
if it exists. -
relative: false
- create links relative todest
. -
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
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
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
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 callsFile.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
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 callsFile.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
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 removingsrc
(that is, ifsrc
anddest
are on different file systems), ignores raised exceptions of StandardError and its descendants. -
noop: true
- does not move files. -
secure: true
- removessrc
securely; see details atFileUtils.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
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
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
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
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
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
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
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
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; returnsnil
. -
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
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
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; returnsnil
. -
secure: true
- removessrc
securely; see details atFileUtils.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
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
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
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; returnsnil
. -
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
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
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
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; returnsnil
. -
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
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
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; ifnil
or-1
, the user is not changed. -
Argument
group
may be a group name or a group id; ifnil
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; returnsnil
. -
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
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
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
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
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
- ifsrc
is a symbolic link, follows the link. -
preserve: true
- preserves file times. -
remove_destination: true
- removesdest
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
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
- ifsrc
is a symbolic link, does not follow the link. -
preserve: true
- preserves file times. -
remove_destination: true
- removesdest
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
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
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
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
- ifsrc
is a symbolic link, does not dereference it. -
noop: true
- does not create links. -
remove_destination: true
- removesdest
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
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
- ifsrc
is a symbolic link, does not dereference it. -
noop: true
- does not copy files. -
preserve: true
- preserves file times. -
remove_destination: true
- removesdest
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
# 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
# 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
# File fileutils.rb, line 2546 def fu_starting_path?(path) path&.start_with?(%r(\w:|/)) end
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 notnil
, using File.chown. -
mode: permissions
- changes the permissions. using File.chmod. -
noop: true
- does not copy entries; returnsnil
. -
owner: owner
- changes the owner if notnil
, 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
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
- dereferencessrc
if it is a symbolic link. -
remove_destination: true
- removesdest
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
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
- overwritesdest
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
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 atdest
pointing tosrc
: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 atdest
pointing tosrc
if and only if keyword argumentforce: 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
- overwritesdest
if it exists. -
relative: false
- create links relative todest
. -
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
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
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
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 callsFile.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
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 callsFile.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
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 removingsrc
(that is, ifsrc
anddest
are on different file systems), ignores raised exceptions of StandardError and its descendants. -
noop: true
- does not move files. -
secure: true
- removessrc
securely; see details atFileUtils.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
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
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
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
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
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
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; returnsnil
. -
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
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
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; returnsnil
. -
secure: true
- removessrc
securely; see details atFileUtils.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
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
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
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; returnsnil
. -
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
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