模块 FileUtils

用于复制、移动、删除等操作的文件实用方法命名空间。

此处内容

首先,其他位置的内容。模块 FileUtils

此处,模块 FileUtils 提供了对以下操作有用的方法

创建

删除

查询

设置

比较

复制

移动

选项

路径参数

FileUtils 中的某些方法接受路径参数,这些参数被解释为文件系统项的路径

关于示例

此处的一些示例涉及文件项的树。对于这些示例,我们有时使用 tree 命令行实用程序 来显示树,这是一个递归目录列表实用程序,可生成文件和目录的深度缩进列表。

我们使用一个辅助方法来启动命令并控制格式

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

举例说明

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

避免 TOCTTOU 漏洞

对于递归删除项的某些方法,存在一个称为 时间检查到时间使用 或 TOCTTOU 的潜在漏洞,当

要避免该漏洞,可以使用此方法来删除项

还可以使用以下方法,每个方法都会调用 FileUtils.remove_entry_secure

最后,此移动项的方法在源和目标位于不同文件系统上时调用 FileUtils.remove_entry_secure(这意味着“移动”实际上是复制和删除)

方法 FileUtils.remove_entry_secure 通过应用特殊预处理来安全删除

警告:您必须确保所有父目录不能被其他不受信任的用户移动。例如,父目录不应归不受信任的用户所有,并且在未设置粘滞位时不应可世界写入。

有关此安全漏洞的详细信息,请参阅 Perl 案例

常量

VERSION

公共类方法

cd(dir, verbose: nil) { |dir| ... } 单击以切换源

将工作目录更改为给定的 dir,该目录应 可解释为路径

如果没有给定块,则将当前目录更改为 dir 中的目录;返回零

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

如果给定块,则将当前目录更改为 dir 中的目录,使用参数 dir 调用块,并还原原始当前目录;返回块的值

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

关键字参数

  • verbose: true - 打印等效命令

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

    输出

    cd ..
    cd fileutils

相关:FileUtils.pwd

# File lib/fileutils.rb, line 238
def cd(dir, verbose: nil, &block) # :yield: dir
  fu_output_message "cd #{dir}" if verbose
  result = Dir.chdir(dir, &block)
  fu_output_message 'cd -' if verbose and block
  result
end
别名也为:chdir
chdir(dir, verbose: nil)
别名:cd
chmod(mode, list, noop: nil, verbose: nil) 单击以切换源

list(单个路径或路径数组)中给定路径处的条目的权限更改为 mode 给定的权限;如果 list 是数组,则返回 list,否则返回 [list]

  • 使用 File.chmod 修改每个常规文件条目。

  • 使用 File.lchmod 修改每个符号链接条目。

参数 list 或其元素应 可解释为路径

参数 mode 可以是整数或字符串

  • 整数 mode:表示要设置的权限位

    FileUtils.chmod(0755, 'src0.txt')
    FileUtils.chmod(0644, ['src0.txt', 'src0.dat'])
    
  • 字符串 mode:表示要设置的权限

    字符串的格式为 [targets][[operator][perms[,perms]],其中

    • targets 可以是以下字母的任意组合

      • 'u':权限适用于文件的拥有者。

      • 'g':权限适用于文件所在组中的用户。

      • 'o':权限适用于文件所在组之外的其他用户。

      • 'a'(默认值):权限适用于所有用户。

    • operator 可以是以下字母之一

      • '+':添加权限。

      • '-':移除权限。

      • '=':设置(替换)权限。

    • perms(可以重复,用逗号分隔)可以是这些字母的任意组合

      • 'r':读取。

      • 'w':写入。

      • 'x':执行(搜索,对于目录)。

      • 'X':搜索(仅限目录;必须与 '+' 一起使用)

      • 's':Uid 或 gid。

      • 't':Sticky 位。

    示例

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

关键字参数

  • noop: true - 不更改权限;返回 nil

  • verbose: true - 打印等效命令

    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)
    

    输出

    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

相关:FileUtils.chmod_R

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

FileUtils.chmod 类似,但会递归更改权限。

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

list(单个路径或路径数组)中给定路径的条目上的所有者和组更改为给定的 usergroup;如果它是一个数组,则返回 list,否则返回 [list]

  • 使用 File.chown 修改每个常规文件条目。

  • 使用 File.lchown 修改每个符号链接条目。

参数 list 或其元素应 可解释为路径

用户和组

  • 参数 user 可以是用户名或用户 ID;如果为 nil-1,则不会更改用户。

  • 参数 group 可以是组名或组 ID;如果为 nil-1,则不会更改组。

  • 用户必须是组的成员。

示例

# 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', '.')

关键字参数

  • noop: true - 不更改权限;返回 nil

  • verbose: true - 打印等效命令

    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)
    

    输出

    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 .

相关:FileUtils.chown_R

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

FileUtils.chown 类似,但会递归更改所有者和组。

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

返回一个字符串方法名数组,这些方法名接受给定的关键字选项 opt;参数必须是一个符号

FileUtils.collect_method(:preserve) # => ["cp", "copy", "cp_r", "install"]
# File lib/fileutils.rb, line 2609
def self.collect_method(opt)
  OPT_TABLE.keys.select {|m| OPT_TABLE[m].include?(opt) }
end
commands() 单击切换源

返回一个字符串名称数组,这些名称是 FileUtils 方法,它们接受一个或多个关键字参数

FileUtils.commands.sort.take(3) # => ["cd", "chdir", "chmod"]
# File lib/fileutils.rb, line 2570
def self.commands
  OPT_TABLE.keys
end
compare_file(a, b) 单击切换源

如果文件 ab 的内容相同,则返回 true,否则返回 false

参数 ab可解释为路径

FileUtils.identical?FileUtils.cmpFileUtils.compare_file 的别名。

相关:FileUtils.compare_stream

# File lib/fileutils.rb, line 1507
def compare_file(a, b)
  return false unless File.size(a) == File.size(b)
  File.open(a, 'rb') {|fa|
    File.open(b, 'rb') {|fb|
      return compare_stream(fa, fb)
    }
  }
end
也别名为:identical?cmp
compare_stream(a, b) 点击切换源代码

如果流 ab 的内容相同,则返回 true,否则返回 false

参数 ab可解释为路径

相关:FileUtils.compare_file

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

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

  begin
    a.read(bsize, sa)
    b.read(bsize, sb)
    return true if sa.empty? && sb.empty?
  end while sa == sb
  false
end
copy(src, dest, preserve: nil, noop: nil, verbose: nil)
别名:cp
copy_entry(src, dest, preserve = false, dereference_root = false, remove_destination = false) 点击切换源代码

递归地将文件从 src 复制到 dest

参数 srcdest可解释为路径

如果 src 是文件的路径,则将 src 复制到 dest

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

如果 src 是目录,则递归地将 src 复制到 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

递归复制保留常规文件、目录和符号链接的文件类型;不支持其他文件类型(FIFO 流、设备文件等)。

关键字参数

  • dereference_root: true - 如果 src 是符号链接,则跟随链接。

  • preserve: true - 保留文件时间。

  • remove_destination: true - 在复制文件之前删除 dest

相关:复制方法

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

  Entry_.new(src, nil, false).wrap_traverse(proc do |ent|
    destent = Entry_.new(dest, ent.rel, false)
    File.unlink destent.path if remove_destination && (File.file?(destent.path) || File.symlink?(destent.path))
    ent.copy destent.path
  end, proc do |ent|
    destent = Entry_.new(dest, ent.rel, false)
    ent.copy_metadata destent.path if preserve
  end)
end
copy_file(src, dest, preserve = false, dereference = true) 点击切换源代码

将文件从 src 复制到 dest,它们不应是目录。

参数 srcdest可解释为路径

示例

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

关键字参数

  • dereference: false - 如果 src 是符号链接,则不跟随链接。

  • preserve: true - 保留文件时间。

  • remove_destination: true - 在复制文件之前删除 dest

相关:复制方法

# File lib/fileutils.rb, line 1076
def copy_file(src, dest, preserve = false, dereference = true)
  ent = Entry_.new(src, nil, dereference)
  ent.copy_file dest
  ent.copy_metadata dest if preserve
end
copy_stream(src, dest) 点击切换源代码

通过 IO.copy_stream 将 IO 流 src 复制到 IO 流 dest

相关:复制方法

# File lib/fileutils.rb, line 1088
def copy_stream(src, dest)
  IO.copy_stream(src, dest)
end
cp(src, dest, preserve: nil, noop: nil, verbose: nil) 单击以切换源

复制文件。

参数 src(单个路径或路径数组)和 dest(单个路径)应 可解释为路径

如果 src 是文件路径且 dest 不是目录路径,则将 src 复制到 dest

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

如果 src 是文件路径且 dest 是目录路径,则将 src 复制到 dest/src

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

如果 src 是文件路径数组且 dest 是目录路径,则从每个 src 复制到 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

关键字参数

  • preserve: true - 保留文件时间。

  • noop: true - 不复制文件。

  • verbose: true - 打印等效命令

    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)
    

    输出

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

如果 src 是目录,则引发异常。

相关:复制方法

# File lib/fileutils.rb, line 873
def cp(src, dest, preserve: nil, noop: nil, verbose: nil)
  fu_output_message "cp#{preserve ? ' -p' : ''} #{[src,dest].flatten.join ' '}" if verbose
  return if noop
  fu_each_src_dest(src, dest) do |s, d|
    copy_file s, d, preserve
  end
end
别名:copy
cp_lr(src, dest, noop: nil, verbose: nil, dereference_root: true, remove_destination: false) 单击以切换源

创建 硬链接

参数 src(单个路径或路径数组)和 dest(单个路径)应 可解释为路径

如果 src 是目录路径且 dest 不存在,则创建指向 src 及其后代的链接 dest 及其后代

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

如果 srcdest 都是目录路径,则创建指向 src 及其后代的链接 dest/src 及其后代

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

如果 src 是条目路径数组且 dest 是目录路径,则对于 src 中的每个路径 filepath,在 dest/filepath 创建指向该路径的链接

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

关键字参数

  • dereference_root: false - 如果 src 是符号链接,则不取消引用。

  • noop: true - 不创建链接。

  • remove_destination: true - 在创建链接之前删除 dest

  • verbose: true - 打印等效命令

    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)
    

    输出

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

如果 dest 是现有文件或目录的路径且未提供关键字参数 remove_destination: true,则引发异常。

相关:复制方法

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

递归复制文件。

参数 src(单个路径或路径数组)和 dest(单个路径)应 可解释为路径

复制中保留模式、所有者和组;要更改这些内容,请改用 FileUtils.install

如果 src 是文件路径且 dest 不是目录路径,则将 src 复制到 dest

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

如果 src 是文件路径且 dest 是目录路径,则将 src 复制到 dest/src

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

如果 src 是目录路径且 dest 不存在,则将 src 递归复制到 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

如果 srcdest 是目录的路径,则递归地将 src 复制到 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

如果 src 是路径数组,而 dest 是目录,则从 src 中的每条路径递归地复制到 destsrc 中的路径可以指向文件和/或目录。

关键字参数

  • dereference_root: false - 如果 src 是符号链接,则不取消引用。

  • noop: true - 不复制文件。

  • preserve: true - 保留文件时间。

  • remove_destination: true - 在复制文件之前删除 dest

  • verbose: true - 打印等效命令

    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)
    

    输出

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

如果 src 是目录的路径,而 dest 是文件的路径,则引发异常。

相关:复制方法

# File lib/fileutils.rb, line 985
def cp_r(src, dest, preserve: nil, noop: nil, verbose: nil,
         dereference_root: true, remove_destination: nil)
  fu_output_message "cp -r#{preserve ? 'p' : ''}#{remove_destination ? ' --remove-destination' : ''} #{[src,dest].flatten.join ' '}" if verbose
  return if noop
  fu_each_src_dest(src, dest) do |s, d|
    copy_entry s, d, preserve, dereference_root, remove_destination
  end
end
getwd()
别名:pwd
have_option?(mid, opt) 单击以切换源

如果方法 mid 接受给定的选项 opt,则返回 true,否则返回 false;参数可以是字符串或符号

FileUtils.have_option?(:chmod, :noop) # => true
FileUtils.have_option?('chmod', 'secure') # => false
# File lib/fileutils.rb, line 2588
def self.have_option?(mid, opt)
  li = OPT_TABLE[mid.to_s] or raise ArgumentError, "no such method: #{mid}"
  li.include?(opt)
end
identical?(a, b)
别名:compare_file
install(src, dest, mode: nil, owner: nil, group: nil, preserve: nil, noop: nil, verbose: nil) 单击以切换源

复制文件条目。请参阅 install(1)

参数 src(单个路径或路径数组)和 dest(单个路径)应可解释为路径

如果 dest 处的条目不存在,则从 src 复制到 dest

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

如果 dest 是文件条目,则从 src 复制到 dest,覆盖

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

如果 dest 是目录条目,则从 src 复制到 dest/src,必要时覆盖

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"

如果 src 是路径数组,而 dest 指向目录,则将 src 中的每条路径 path 复制到 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

关键字参数

  • group: group - 如果不为 nil,则使用 File.chown 更改组。

  • mode: permissions - 更改权限。使用 File.chmod

  • noop: true - 不复制条目;返回 nil

  • owner: owner - 如果不为 nil,则使用 File.chown 更改所有者。

  • preserve: true - 使用 File.utime 保留时间戳。

  • verbose: true - 打印等效命令

    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)
    

    输出

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

相关:复制方法

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

创建 硬链接;返回 nil

参数 srcdest可解释为路径

如果 src 是文件路径且 dest 不存在,则在 dest 创建指向 src 的硬链接

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

如果 src 是目录路径且 dest 不存在,则在 dest 递归创建指向 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

关键字参数

  • dereference_root: true - 如果 src 是符号链接,则取消引用。

  • remove_destination: true - 在创建链接之前删除 dest

如果 dest 是现有文件或目录的路径且未提供关键字参数 remove_destination: true,则引发异常。

相关:FileUtils.ln(选项不同)。

# File lib/fileutils.rb, line 812
def link_entry(src, dest, dereference_root = false, remove_destination = false)
  Entry_.new(src, nil, dereference_root).traverse do |ent|
    destent = Entry_.new(dest, ent.rel, false)
    File.unlink destent.path if remove_destination && File.file?(destent.path)
    ent.link destent.path
  end
end
ln(src, dest, force: nil, noop: nil, verbose: nil) 点击切换源代码

创建 硬链接

参数 src(单个路径或路径数组)和 dest(单个路径)应 可解释为路径

src 是现有文件的路径且 dest 是不存在文件的路径时,在 dest 创建指向 src 的硬链接;返回零

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

src 是现有文件的路径且 dest 是现有目录的路径时,在 dest/src 创建指向 src 的硬链接;返回零

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

src 是现有文件路径的数组且 dest 是现有目录的路径时,则对于 src 中的每个路径 target,在 dest/target 创建指向 target 的硬链接;返回 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"]

关键字参数

  • force: true - 如果 dest 存在,则覆盖它。

  • noop: true - 不创建链接。

  • verbose: true - 打印等效命令

    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)
    

    输出

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

如果 dest 是现有文件的路径且关键字参数 force 不是 true,则引发异常。

相关:FileUtils.link_entry(选项不同)。

# File lib/fileutils.rb, line 516
def ln(src, dest, force: nil, noop: nil, verbose: nil)
  fu_output_message "ln#{force ? ' -f' : ''} #{[src,dest].flatten.join ' '}" if verbose
  return if noop
  fu_each_src_dest0(src, dest) do |s,d|
    remove_file d, true if force
    File.link s, d
  end
end
别名:link
ln_s(src, dest, force: nil, relative: false, target_directory: true, noop: nil, verbose: nil) 点击切换源代码

创建 符号链接

参数 src(单个路径或路径数组)和 dest(单个路径)应 可解释为路径

如果 src 是现有文件的路径

  • dest 是指向不存在文件的路径时,在 dest 创建一个指向 src 的符号链接

    FileUtils.touch('src0.txt')
    File.exist?('dest0.txt')   # => false
    FileUtils.ln_s('src0.txt', 'dest0.txt')
    File.symlink?('dest0.txt') # => true
    
  • dest 是指向现有文件的路径时,仅在给定关键字参数 force: true 时才会在 dest 创建一个指向 src 的符号链接(否则会引发异常)

    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.
    

如果 dest 是指向目录的路径,则在 dest/src 创建一个指向 src 的符号链接

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

如果 src 是指向现有文件的路径数组,且 dest 是目录,则对于 src 中的每个子项 child,都会创建一个指向 child 的符号链接 dest/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

关键字参数

  • force: true - 如果 dest 存在,则覆盖它。

  • relative: false - 相对于 dest 创建链接。

  • noop: true - 不创建链接。

  • verbose: true - 打印等效命令

    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)
    

    输出

    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

相关信息:FileUtils.ln_sf

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

FileUtils.ln_s 类似,但始终给定关键字参数 force: true

# File lib/fileutils.rb, line 724
def ln_sf(src, dest, noop: nil, verbose: nil)
  ln_s src, dest, force: true, noop: noop, verbose: verbose
end
ln_sr(src, dest, target_directory: true, force: nil, noop: nil, verbose: nil) 单击切换源

FileUtils.ln_s 类似,但相对于 dest 创建链接。

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

在给定 list(单个路径或路径数组)中的路径处创建目录;如果它是数组,则返回 list,否则返回 [list]

参数 list 或其元素应 可解释为路径

如果没有关键字参数,则通过调用以下方法在 list 中的每个 path 处创建目录:Dir.mkdir(path, mode);请参阅 Dir.mkdir

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

关键字参数

  • mode: mode - 还会调用 File.chmod(mode, path);请参阅 File.chmod

  • noop: true - 不创建目录。

  • verbose: true - 打印等效命令

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

    输出

    mkdir tmp0 tmp1
    mkdir -m 700 tmp2 tmp3

如果任何路径指向现有文件或目录,或者由于任何原因无法创建目录,则会引发异常。

相关信息:FileUtils.mkdir_p

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

  list.each do |dir|
    fu_mkdir dir, mode
  end
end
mkdir_p(list, mode: nil, noop: nil, verbose: nil) 单击切换源

在给定 list(单个路径或路径数组)中的路径处创建目录,同时根据需要创建祖先目录;如果它是数组,则返回 list,否则返回 [list]

参数 list 或其元素应 可解释为路径

如果没有关键字参数,则在 list 中的每个 path 中创建一个目录,以及任何所需的祖先目录,方法是调用:Dir.mkdir(path, mode);请参阅 Dir.mkdir

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

关键字参数

  • mode: mode - 还会调用 File.chmod(mode, path);请参阅 File.chmod

  • noop: true - 不创建目录。

  • verbose: true - 打印等效命令

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

    输出

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

如果由于任何原因无法创建目录,则引发异常。

FileUtils.mkpathFileUtils.makedirsFileUtils.mkdir_p 的别名。

相关:FileUtils.mkdir

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

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

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

  return *list
end
别名:mkpathmakedirs
mkpath(list, mode: nil, noop: nil, verbose: nil)
别名:mkdir_p
move(src, dest, force: nil, noop: nil, verbose: nil, secure: nil)
别名:mv
mv(src, dest, force: nil, noop: nil, verbose: nil, secure: nil) 单击以切换源

移动条目。

参数 src(单个路径或路径数组)和 dest(单个路径)应 可解释为路径

如果 srcdest 在不同的文件系统上,则先复制,然后删除 src

如果不使用关键字参数 secure: true 调用,则可能导致本地漏洞;请参阅 避免 TOCTTOU 漏洞

如果 src 是单个文件或目录的路径,并且 dest 不存在,则将 src 移动到 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

如果 src 是文件和目录的路径数组,并且 dest 是目录的路径,则从数组中的每个路径复制到 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

关键字参数

  • force: true - 如果移动包括删除 src(即,如果 srcdest 在不同的文件系统上),则忽略引发的 StandardError 及其后代的异常。

  • noop: true - 不移动文件。

  • secure: true - 安全地删除 src;请参阅 FileUtils.remove_entry_secure 中的详细信息。

  • verbose: true - 打印等效命令

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

    输出

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

返回字符串关键字名称的数组

FileUtils.options.take(3) # => ["noop", "verbose", "force"]
# File lib/fileutils.rb, line 2578
def self.options
  OPT_TABLE.values.flatten.uniq.map {|sym| sym.to_s }
end
options_of(mid) 单击以切换源

返回方法 mid 的字符串关键字名称的数组;参数可以是字符串或符号

FileUtils.options_of(:rm) # => ["force", "noop", "verbose"]
FileUtils.options_of('mv') # => ["force", "noop", "verbose", "secure"]
# File lib/fileutils.rb, line 2599
def self.options_of(mid)
  OPT_TABLE[mid.to_s].map {|sym| sym.to_s }
end
pwd() 单击以切换源

返回一个包含当前目录路径的字符串

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

相关:FileUtils.cd

# File lib/fileutils.rb, line 197
def pwd
  Dir.pwd
end
别名:getwd
remove(list, force: nil, noop: nil, verbose: nil)
别名:rm
remove_dir(path, force = false) 单击以切换源

递归删除由 path 给出的目录项,该项应该是常规文件、符号链接或目录的项。

参数 path可解释为路径

可选参数 force 指定是否忽略 StandardError 及其子类的引发异常。

相关:删除方法

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

删除由 path 给出的项,该项应该是常规文件、符号链接或目录的项。

参数 path可解释为路径

可选参数 force 指定是否忽略 StandardError 及其子类的引发异常。

相关:FileUtils.remove_entry_secure

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

安全地删除由 path 给出的项,该项应该是常规文件、符号链接或目录的项。

参数 path可解释为路径

避免在某些情况下可能存在的本地漏洞;请参阅 避免 TOCTTOU 漏洞

可选参数 force 指定是否忽略 StandardError 及其子类的引发异常。

相关:删除方法

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

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

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

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

删除由 path 给出的文件项,该项应该是常规文件或符号链接的项。

参数 path可解释为路径

可选参数 force 指定是否忽略 StandardError 及其子类的引发异常。

相关:删除方法

# File lib/fileutils.rb, line 1473
def remove_file(path, force = false)
  Entry_.new(path).remove_file
rescue
  raise unless force
end
rm(list, force: nil, noop: nil, verbose: nil) 单击以切换源

删除给定list(单个路径或路径数组)中的路径处的条目,如果它是数组,则返回list,否则返回[list]

参数 list 或其元素应 可解释为路径

如果没有关键字参数,则删除list中给定路径处的文件

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

关键字参数

  • force: true - 忽略引发的 StandardError 及其后代的异常。

  • noop: true - 不删除文件;返回nil

  • verbose: true - 打印等效命令

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

    输出

    rm src0.dat src0.txt
    

相关:删除方法

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

  list.each do |path|
    remove_file path, force
  end
end
别名:remove
rm_f(list, noop: nil, verbose: nil) 单击切换源

等同于

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

参数list(单个路径或路径数组)应 可解释为路径

有关关键字参数,请参阅 FileUtils.rm

相关:删除方法

# File lib/fileutils.rb, line 1241
def rm_f(list, noop: nil, verbose: nil)
  rm list, force: true, noop: noop, verbose: verbose
end
别名:safe_unlink
rm_r(list, force: nil, noop: nil, verbose: nil, secure: nil) 单击切换源

删除给定list(单个路径或路径数组)中的路径处的条目;如果它是数组,则返回list,否则返回[list]

参数 list 或其元素应 可解释为路径

如果不使用关键字参数 secure: true 调用,则可能导致本地漏洞;请参阅 避免 TOCTTOU 漏洞

对于每个文件路径,删除该路径处的文件

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

对于每个目录路径,递归删除文件和目录

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

关键字参数

  • force: true - 忽略引发的 StandardError 及其后代的异常。

  • noop: true - 不删除条目;返回nil

  • secure: true - 安全地删除 src;请参阅 FileUtils.remove_entry_secure 中的详细信息。

  • verbose: true - 打印等效命令

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

    输出

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

相关:删除方法

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

等同于

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

参数 list 或其元素应 可解释为路径

如果不使用关键字参数 secure: true 调用,则可能导致本地漏洞;请参阅 避免 TOCTTOU 漏洞

有关关键字参数,请参阅 FileUtils.rm_r

相关:删除方法

# File lib/fileutils.rb, line 1328
def rm_rf(list, noop: nil, verbose: nil, secure: nil)
  rm_r list, force: true, noop: noop, verbose: verbose, secure: secure
end
别名:rmtree
rmdir(list, parents: nil, noop: nil, verbose: nil) 单击切换源

删除给定list(单个路径或路径数组)中的路径处的目录;如果它是数组,则返回list,否则返回[list]

参数 list 或其元素应 可解释为路径

如果没有关键字参数,则通过调用:Dir.rmdir(path) 删除list中每个path处的目录;请参阅 Dir.rmdir

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

关键字参数

  • parents: true - 如果为空,则删除连续的祖先目录。

  • noop: true - 不删除目录。

  • verbose: true - 打印等效命令

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

    输出

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

如果目录不存在或由于任何原因无法删除目录,则引发异常。

相关:删除方法

# File lib/fileutils.rb, line 442
def rmdir(list, parents: nil, noop: nil, verbose: nil)
  list = fu_list(list)
  fu_output_message "rmdir #{parents ? '-p ' : ''}#{list.join ' '}" if verbose
  return if noop
  list.each do |dir|
    Dir.rmdir(dir = remove_trailing_slash(dir))
    if parents
      begin
        until (parent = File.dirname(dir)) == '.' or parent == dir
          dir = parent
          Dir.rmdir(dir)
        end
      rescue Errno::ENOTEMPTY, Errno::EEXIST, Errno::ENOENT
      end
    end
  end
end
rmtree(list, noop: nil, verbose: nil, secure: nil)
别名:rm_rf
touch(list, noop: nil, verbose: nil, mtime: nil, nocreate: nil) 点击切换源代码

更新list(单个路径或路径数组)中路径所指定条目的修改时间 (mtime) 和访问时间 (atime);如果它是一个数组,则返回list,否则返回[list]

默认情况下,将为任何不存在的条目路径创建一个空文件;使用关键字参数nocreate可以改为引发异常。

参数 list 或其元素应 可解释为路径

示例

# 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'])

关键字参数

  • mtime: time - 将条目的 mtime 设置为给定时间,而不是当前时间。

  • nocreate: true - 如果条目不存在,则引发异常。

  • noop: true - 不触摸条目;返回nil

  • verbose: true - 打印等效命令

    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)
    

    输出

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

相关:FileUtils.uptodate?

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

如果路径new处的文件比数组old_list中所有路径处的文件都新,则返回true;否则返回false

参数newold_list的元素应可解释为路径

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

不存在的文件被认为是无限旧的。

相关:FileUtils.touch

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

私有实例方法

cd(dir, verbose: nil) { |dir| ... } 单击以切换源

将工作目录更改为给定的 dir,该目录应 可解释为路径

如果没有给定块,则将当前目录更改为 dir 中的目录;返回零

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

如果给定块,则将当前目录更改为 dir 中的目录,使用参数 dir 调用块,并还原原始当前目录;返回块的值

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

关键字参数

  • verbose: true - 打印等效命令

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

    输出

    cd ..
    cd fileutils

相关:FileUtils.pwd

# File lib/fileutils.rb, line 238
def cd(dir, verbose: nil, &block) # :yield: dir
  fu_output_message "cd #{dir}" if verbose
  result = Dir.chdir(dir, &block)
  fu_output_message 'cd -' if verbose and block
  result
end
别名也为:chdir
chdir(dir, verbose: nil)
别名:cd
chmod(mode, list, noop: nil, verbose: nil) 单击以切换源

list(单个路径或路径数组)中给定路径处的条目的权限更改为 mode 给定的权限;如果 list 是数组,则返回 list,否则返回 [list]

  • 使用 File.chmod 修改每个常规文件条目。

  • 使用 File.lchmod 修改每个符号链接条目。

参数 list 或其元素应 可解释为路径

参数 mode 可以是整数或字符串

  • 整数 mode:表示要设置的权限位

    FileUtils.chmod(0755, 'src0.txt')
    FileUtils.chmod(0644, ['src0.txt', 'src0.dat'])
    
  • 字符串 mode:表示要设置的权限

    字符串的格式为 [targets][[operator][perms[,perms]],其中

    • targets 可以是以下字母的任意组合

      • 'u':权限适用于文件的拥有者。

      • 'g':权限适用于文件所在组中的用户。

      • 'o':权限适用于文件所在组之外的其他用户。

      • 'a'(默认值):权限适用于所有用户。

    • operator 可以是以下字母之一

      • '+':添加权限。

      • '-':移除权限。

      • '=':设置(替换)权限。

    • perms(可以重复,用逗号分隔)可以是这些字母的任意组合

      • 'r':读取。

      • 'w':写入。

      • 'x':执行(搜索,对于目录)。

      • 'X':搜索(仅限目录;必须与 '+' 一起使用)

      • 's':Uid 或 gid。

      • 't':Sticky 位。

    示例

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

关键字参数

  • noop: true - 不更改权限;返回 nil

  • verbose: true - 打印等效命令

    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)
    

    输出

    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

相关:FileUtils.chmod_R

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

FileUtils.chmod 类似,但会递归更改权限。

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

list(单个路径或路径数组)中给定路径的条目上的所有者和组更改为给定的 usergroup;如果它是一个数组,则返回 list,否则返回 [list]

  • 使用 File.chown 修改每个常规文件条目。

  • 使用 File.lchown 修改每个符号链接条目。

参数 list 或其元素应 可解释为路径

用户和组

  • 参数 user 可以是用户名或用户 ID;如果为 nil-1,则不会更改用户。

  • 参数 group 可以是组名或组 ID;如果为 nil-1,则不会更改组。

  • 用户必须是组的成员。

示例

# 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', '.')

关键字参数

  • noop: true - 不更改权限;返回 nil

  • verbose: true - 打印等效命令

    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)
    

    输出

    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 .

相关:FileUtils.chown_R

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

FileUtils.chown 类似,但会递归更改所有者和组。

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

如果文件 ab 的内容相同,则返回 true,否则返回 false

参数 ab可解释为路径

FileUtils.identical?FileUtils.cmpFileUtils.compare_file 的别名。

相关:FileUtils.compare_stream

# File lib/fileutils.rb, line 1507
def compare_file(a, b)
  return false unless File.size(a) == File.size(b)
  File.open(a, 'rb') {|fa|
    File.open(b, 'rb') {|fb|
      return compare_stream(fa, fb)
    }
  }
end
也别名为:identical?cmp
compare_stream(a, b) 点击切换源代码

如果流 ab 的内容相同,则返回 true,否则返回 false

参数 ab可解释为路径

相关:FileUtils.compare_file

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

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

  begin
    a.read(bsize, sa)
    b.read(bsize, sb)
    return true if sa.empty? && sb.empty?
  end while sa == sb
  false
end
copy(src, dest, preserve: nil, noop: nil, verbose: nil)
别名:cp
copy_entry(src, dest, preserve = false, dereference_root = false, remove_destination = false) 点击切换源代码

递归地将文件从 src 复制到 dest

参数 srcdest可解释为路径

如果 src 是文件的路径,则将 src 复制到 dest

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

如果 src 是目录,则递归地将 src 复制到 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

递归复制保留常规文件、目录和符号链接的文件类型;不支持其他文件类型(FIFO 流、设备文件等)。

关键字参数

  • dereference_root: true - 如果 src 是符号链接,则跟随链接。

  • preserve: true - 保留文件时间。

  • remove_destination: true - 在复制文件之前删除 dest

相关:复制方法

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

  Entry_.new(src, nil, false).wrap_traverse(proc do |ent|
    destent = Entry_.new(dest, ent.rel, false)
    File.unlink destent.path if remove_destination && (File.file?(destent.path) || File.symlink?(destent.path))
    ent.copy destent.path
  end, proc do |ent|
    destent = Entry_.new(dest, ent.rel, false)
    ent.copy_metadata destent.path if preserve
  end)
end
copy_file(src, dest, preserve = false, dereference = true) 点击切换源代码

将文件从 src 复制到 dest,它们不应是目录。

参数 srcdest可解释为路径

示例

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

关键字参数

  • dereference: false - 如果 src 是符号链接,则不跟随链接。

  • preserve: true - 保留文件时间。

  • remove_destination: true - 在复制文件之前删除 dest

相关:复制方法

# File lib/fileutils.rb, line 1076
def copy_file(src, dest, preserve = false, dereference = true)
  ent = Entry_.new(src, nil, dereference)
  ent.copy_file dest
  ent.copy_metadata dest if preserve
end
copy_stream(src, dest) 点击切换源代码

通过 IO.copy_stream 将 IO 流 src 复制到 IO 流 dest

相关:复制方法

# File lib/fileutils.rb, line 1088
def copy_stream(src, dest)
  IO.copy_stream(src, dest)
end
cp(src, dest, preserve: nil, noop: nil, verbose: nil) 单击以切换源

复制文件。

参数 src(单个路径或路径数组)和 dest(单个路径)应 可解释为路径

如果 src 是文件路径且 dest 不是目录路径,则将 src 复制到 dest

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

如果 src 是文件路径且 dest 是目录路径,则将 src 复制到 dest/src

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

如果 src 是文件路径数组且 dest 是目录路径,则从每个 src 复制到 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

关键字参数

  • preserve: true - 保留文件时间。

  • noop: true - 不复制文件。

  • verbose: true - 打印等效命令

    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)
    

    输出

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

如果 src 是目录,则引发异常。

相关:复制方法

# File lib/fileutils.rb, line 873
def cp(src, dest, preserve: nil, noop: nil, verbose: nil)
  fu_output_message "cp#{preserve ? ' -p' : ''} #{[src,dest].flatten.join ' '}" if verbose
  return if noop
  fu_each_src_dest(src, dest) do |s, d|
    copy_file s, d, preserve
  end
end
别名:copy
cp_lr(src, dest, noop: nil, verbose: nil, dereference_root: true, remove_destination: false) 单击以切换源

创建 硬链接

参数 src(单个路径或路径数组)和 dest(单个路径)应 可解释为路径

如果 src 是目录路径且 dest 不存在,则创建指向 src 及其后代的链接 dest 及其后代

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

如果 srcdest 都是目录路径,则创建指向 src 及其后代的链接 dest/src 及其后代

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

如果 src 是条目路径数组且 dest 是目录路径,则对于 src 中的每个路径 filepath,在 dest/filepath 创建指向该路径的链接

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

关键字参数

  • dereference_root: false - 如果 src 是符号链接,则不取消引用。

  • noop: true - 不创建链接。

  • remove_destination: true - 在创建链接之前删除 dest

  • verbose: true - 打印等效命令

    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)
    

    输出

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

如果 dest 是现有文件或目录的路径且未提供关键字参数 remove_destination: true,则引发异常。

相关:复制方法

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

递归复制文件。

参数 src(单个路径或路径数组)和 dest(单个路径)应 可解释为路径

复制中保留模式、所有者和组;要更改这些内容,请改用 FileUtils.install

如果 src 是文件路径且 dest 不是目录路径,则将 src 复制到 dest

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

如果 src 是文件路径且 dest 是目录路径,则将 src 复制到 dest/src

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

如果 src 是目录路径且 dest 不存在,则将 src 递归复制到 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

如果 srcdest 是目录的路径,则递归地将 src 复制到 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

如果 src 是路径数组,而 dest 是目录,则从 src 中的每条路径递归地复制到 destsrc 中的路径可以指向文件和/或目录。

关键字参数

  • dereference_root: false - 如果 src 是符号链接,则不取消引用。

  • noop: true - 不复制文件。

  • preserve: true - 保留文件时间。

  • remove_destination: true - 在复制文件之前删除 dest

  • verbose: true - 打印等效命令

    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)
    

    输出

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

如果 src 是目录的路径,而 dest 是文件的路径,则引发异常。

相关:复制方法

# File lib/fileutils.rb, line 985
def cp_r(src, dest, preserve: nil, noop: nil, verbose: nil,
         dereference_root: true, remove_destination: nil)
  fu_output_message "cp -r#{preserve ? 'p' : ''}#{remove_destination ? ' --remove-destination' : ''} #{[src,dest].flatten.join ' '}" if verbose
  return if noop
  fu_each_src_dest(src, dest) do |s, d|
    copy_entry s, d, preserve, dereference_root, remove_destination
  end
end
fu_clean_components(*comp) 点击切换源代码
# File lib/fileutils.rb, line 2527
def fu_clean_components(*comp)
  comp.shift while comp.first == "."
  return comp if comp.empty?
  clean = [comp.shift]
  path = File.join(*clean, "") # ending with File::SEPARATOR
  while c = comp.shift
    if c == ".." and clean.last != ".." and !(fu_have_symlink? && File.symlink?(path))
      clean.pop
      path.chomp!(%r((?<=\A|/)[^/]+/\z), "")
    else
      clean << c
      path << c << "/"
    end
  end
  clean
end
fu_split_path(path) 点击切换源代码
# File lib/fileutils.rb, line 2506
def fu_split_path(path)
  path = File.path(path)
  list = []
  until (parent, base = File.split(path); parent == path or parent == ".")
    list << base
    path = parent
  end
  list << path
  list.reverse!
end
fu_starting_path?(path) 点击切换源代码
# File lib/fileutils.rb, line 2546
def fu_starting_path?(path)
  path&.start_with?(%r(\w:|/))
end
getwd()
别名:pwd
identical?(a, b)
别名:compare_file
install(src, dest, mode: nil, owner: nil, group: nil, preserve: nil, noop: nil, verbose: nil) 单击以切换源

复制文件条目。请参阅 install(1)

参数 src(单个路径或路径数组)和 dest(单个路径)应可解释为路径

如果 dest 处的条目不存在,则从 src 复制到 dest

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

如果 dest 是文件条目,则从 src 复制到 dest,覆盖

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

如果 dest 是目录条目,则从 src 复制到 dest/src,必要时覆盖

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"

如果 src 是路径数组,而 dest 指向目录,则将 src 中的每条路径 path 复制到 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

关键字参数

  • group: group - 如果不为 nil,则使用 File.chown 更改组。

  • mode: permissions - 更改权限。使用 File.chmod

  • noop: true - 不复制条目;返回 nil

  • owner: owner - 如果不为 nil,则使用 File.chown 更改所有者。

  • preserve: true - 使用 File.utime 保留时间戳。

  • verbose: true - 打印等效命令

    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)
    

    输出

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

相关:复制方法

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

创建 硬链接;返回 nil

参数 srcdest可解释为路径

如果 src 是文件路径且 dest 不存在,则在 dest 创建指向 src 的硬链接

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

如果 src 是目录路径且 dest 不存在,则在 dest 递归创建指向 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

关键字参数

  • dereference_root: true - 如果 src 是符号链接,则取消引用。

  • remove_destination: true - 在创建链接之前删除 dest

如果 dest 是现有文件或目录的路径且未提供关键字参数 remove_destination: true,则引发异常。

相关:FileUtils.ln(选项不同)。

# File lib/fileutils.rb, line 812
def link_entry(src, dest, dereference_root = false, remove_destination = false)
  Entry_.new(src, nil, dereference_root).traverse do |ent|
    destent = Entry_.new(dest, ent.rel, false)
    File.unlink destent.path if remove_destination && File.file?(destent.path)
    ent.link destent.path
  end
end
ln(src, dest, force: nil, noop: nil, verbose: nil) 点击切换源代码

创建 硬链接

参数 src(单个路径或路径数组)和 dest(单个路径)应 可解释为路径

src 是现有文件的路径且 dest 是不存在文件的路径时,在 dest 创建指向 src 的硬链接;返回零

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

src 是现有文件的路径且 dest 是现有目录的路径时,在 dest/src 创建指向 src 的硬链接;返回零

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

src 是现有文件路径的数组且 dest 是现有目录的路径时,则对于 src 中的每个路径 target,在 dest/target 创建指向 target 的硬链接;返回 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"]

关键字参数

  • force: true - 如果 dest 存在,则覆盖它。

  • noop: true - 不创建链接。

  • verbose: true - 打印等效命令

    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)
    

    输出

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

如果 dest 是现有文件的路径且关键字参数 force 不是 true,则引发异常。

相关:FileUtils.link_entry(选项不同)。

# File lib/fileutils.rb, line 516
def ln(src, dest, force: nil, noop: nil, verbose: nil)
  fu_output_message "ln#{force ? ' -f' : ''} #{[src,dest].flatten.join ' '}" if verbose
  return if noop
  fu_each_src_dest0(src, dest) do |s,d|
    remove_file d, true if force
    File.link s, d
  end
end
别名:link
ln_s(src, dest, force: nil, relative: false, target_directory: true, noop: nil, verbose: nil) 点击切换源代码

创建 符号链接

参数 src(单个路径或路径数组)和 dest(单个路径)应 可解释为路径

如果 src 是现有文件的路径

  • dest 是指向不存在文件的路径时,在 dest 创建一个指向 src 的符号链接

    FileUtils.touch('src0.txt')
    File.exist?('dest0.txt')   # => false
    FileUtils.ln_s('src0.txt', 'dest0.txt')
    File.symlink?('dest0.txt') # => true
    
  • dest 是指向现有文件的路径时,仅在给定关键字参数 force: true 时才会在 dest 创建一个指向 src 的符号链接(否则会引发异常)

    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.
    

如果 dest 是指向目录的路径,则在 dest/src 创建一个指向 src 的符号链接

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

如果 src 是指向现有文件的路径数组,且 dest 是目录,则对于 src 中的每个子项 child,都会创建一个指向 child 的符号链接 dest/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

关键字参数

  • force: true - 如果 dest 存在,则覆盖它。

  • relative: false - 相对于 dest 创建链接。

  • noop: true - 不创建链接。

  • verbose: true - 打印等效命令

    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)
    

    输出

    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

相关信息:FileUtils.ln_sf

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

FileUtils.ln_s 类似,但始终给定关键字参数 force: true

# File lib/fileutils.rb, line 724
def ln_sf(src, dest, noop: nil, verbose: nil)
  ln_s src, dest, force: true, noop: noop, verbose: verbose
end
ln_sr(src, dest, target_directory: true, force: nil, noop: nil, verbose: nil) 单击切换源

FileUtils.ln_s 类似,但相对于 dest 创建链接。

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

在给定 list(单个路径或路径数组)中的路径处创建目录;如果它是数组,则返回 list,否则返回 [list]

参数 list 或其元素应 可解释为路径

如果没有关键字参数,则通过调用以下方法在 list 中的每个 path 处创建目录:Dir.mkdir(path, mode);请参阅 Dir.mkdir

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

关键字参数

  • mode: mode - 还会调用 File.chmod(mode, path);请参阅 File.chmod

  • noop: true - 不创建目录。

  • verbose: true - 打印等效命令

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

    输出

    mkdir tmp0 tmp1
    mkdir -m 700 tmp2 tmp3

如果任何路径指向现有文件或目录,或者由于任何原因无法创建目录,则会引发异常。

相关信息:FileUtils.mkdir_p

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

  list.each do |dir|
    fu_mkdir dir, mode
  end
end
mkdir_p(list, mode: nil, noop: nil, verbose: nil) 单击切换源

在给定 list(单个路径或路径数组)中的路径处创建目录,同时根据需要创建祖先目录;如果它是数组,则返回 list,否则返回 [list]

参数 list 或其元素应 可解释为路径

如果没有关键字参数,则在 list 中的每个 path 中创建一个目录,以及任何所需的祖先目录,方法是调用:Dir.mkdir(path, mode);请参阅 Dir.mkdir

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

关键字参数

  • mode: mode - 还会调用 File.chmod(mode, path);请参阅 File.chmod

  • noop: true - 不创建目录。

  • verbose: true - 打印等效命令

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

    输出

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

如果由于任何原因无法创建目录,则引发异常。

FileUtils.mkpathFileUtils.makedirsFileUtils.mkdir_p 的别名。

相关:FileUtils.mkdir

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

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

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

  return *list
end
别名:mkpathmakedirs
mkpath(list, mode: nil, noop: nil, verbose: nil)
别名:mkdir_p
move(src, dest, force: nil, noop: nil, verbose: nil, secure: nil)
别名:mv
mv(src, dest, force: nil, noop: nil, verbose: nil, secure: nil) 单击以切换源

移动条目。

参数 src(单个路径或路径数组)和 dest(单个路径)应 可解释为路径

如果 srcdest 在不同的文件系统上,则先复制,然后删除 src

如果不使用关键字参数 secure: true 调用,则可能导致本地漏洞;请参阅 避免 TOCTTOU 漏洞

如果 src 是单个文件或目录的路径,并且 dest 不存在,则将 src 移动到 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

如果 src 是文件和目录的路径数组,并且 dest 是目录的路径,则从数组中的每个路径复制到 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

关键字参数

  • force: true - 如果移动包括删除 src(即,如果 srcdest 在不同的文件系统上),则忽略引发的 StandardError 及其后代的异常。

  • noop: true - 不移动文件。

  • secure: true - 安全地删除 src;请参阅 FileUtils.remove_entry_secure 中的详细信息。

  • verbose: true - 打印等效命令

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

    输出

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

返回一个包含当前目录路径的字符串

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

相关:FileUtils.cd

# File lib/fileutils.rb, line 197
def pwd
  Dir.pwd
end
别名:getwd
remove(list, force: nil, noop: nil, verbose: nil)
别名:rm
remove_dir(path, force = false) 单击以切换源

递归删除由 path 给出的目录项,该项应该是常规文件、符号链接或目录的项。

参数 path可解释为路径

可选参数 force 指定是否忽略 StandardError 及其子类的引发异常。

相关:删除方法

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

删除由 path 给出的项,该项应该是常规文件、符号链接或目录的项。

参数 path可解释为路径

可选参数 force 指定是否忽略 StandardError 及其子类的引发异常。

相关:FileUtils.remove_entry_secure

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

安全地删除由 path 给出的项,该项应该是常规文件、符号链接或目录的项。

参数 path可解释为路径

避免在某些情况下可能存在的本地漏洞;请参阅 避免 TOCTTOU 漏洞

可选参数 force 指定是否忽略 StandardError 及其子类的引发异常。

相关:删除方法

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

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

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

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

删除由 path 给出的文件项,该项应该是常规文件或符号链接的项。

参数 path可解释为路径

可选参数 force 指定是否忽略 StandardError 及其子类的引发异常。

相关:删除方法

# File lib/fileutils.rb, line 1473
def remove_file(path, force = false)
  Entry_.new(path).remove_file
rescue
  raise unless force
end
rm(list, force: nil, noop: nil, verbose: nil) 单击以切换源

删除给定list(单个路径或路径数组)中的路径处的条目,如果它是数组,则返回list,否则返回[list]

参数 list 或其元素应 可解释为路径

如果没有关键字参数,则删除list中给定路径处的文件

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

关键字参数

  • force: true - 忽略引发的 StandardError 及其后代的异常。

  • noop: true - 不删除文件;返回nil

  • verbose: true - 打印等效命令

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

    输出

    rm src0.dat src0.txt
    

相关:删除方法

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

  list.each do |path|
    remove_file path, force
  end
end
别名:remove
rm_f(list, noop: nil, verbose: nil) 单击切换源

等同于

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

参数list(单个路径或路径数组)应 可解释为路径

有关关键字参数,请参阅 FileUtils.rm

相关:删除方法

# File lib/fileutils.rb, line 1241
def rm_f(list, noop: nil, verbose: nil)
  rm list, force: true, noop: noop, verbose: verbose
end
别名:safe_unlink
rm_r(list, force: nil, noop: nil, verbose: nil, secure: nil) 单击切换源

删除给定list(单个路径或路径数组)中的路径处的条目;如果它是数组,则返回list,否则返回[list]

参数 list 或其元素应 可解释为路径

如果不使用关键字参数 secure: true 调用,则可能导致本地漏洞;请参阅 避免 TOCTTOU 漏洞

对于每个文件路径,删除该路径处的文件

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

对于每个目录路径,递归删除文件和目录

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

关键字参数

  • force: true - 忽略引发的 StandardError 及其后代的异常。

  • noop: true - 不删除条目;返回nil

  • secure: true - 安全地删除 src;请参阅 FileUtils.remove_entry_secure 中的详细信息。

  • verbose: true - 打印等效命令

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

    输出

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

相关:删除方法

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

等同于

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

参数 list 或其元素应 可解释为路径

如果不使用关键字参数 secure: true 调用,则可能导致本地漏洞;请参阅 避免 TOCTTOU 漏洞

有关关键字参数,请参阅 FileUtils.rm_r

相关:删除方法

# File lib/fileutils.rb, line 1328
def rm_rf(list, noop: nil, verbose: nil, secure: nil)
  rm_r list, force: true, noop: noop, verbose: verbose, secure: secure
end
别名:rmtree
rmdir(list, parents: nil, noop: nil, verbose: nil) 单击切换源

删除给定list(单个路径或路径数组)中的路径处的目录;如果它是数组,则返回list,否则返回[list]

参数 list 或其元素应 可解释为路径

如果没有关键字参数,则通过调用:Dir.rmdir(path) 删除list中每个path处的目录;请参阅 Dir.rmdir

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

关键字参数

  • parents: true - 如果为空,则删除连续的祖先目录。

  • noop: true - 不删除目录。

  • verbose: true - 打印等效命令

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

    输出

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

如果目录不存在或由于任何原因无法删除目录,则引发异常。

相关:删除方法

# File lib/fileutils.rb, line 442
def rmdir(list, parents: nil, noop: nil, verbose: nil)
  list = fu_list(list)
  fu_output_message "rmdir #{parents ? '-p ' : ''}#{list.join ' '}" if verbose
  return if noop
  list.each do |dir|
    Dir.rmdir(dir = remove_trailing_slash(dir))
    if parents
      begin
        until (parent = File.dirname(dir)) == '.' or parent == dir
          dir = parent
          Dir.rmdir(dir)
        end
      rescue Errno::ENOTEMPTY, Errno::EEXIST, Errno::ENOENT
      end
    end
  end
end
rmtree(list, noop: nil, verbose: nil, secure: nil)
别名:rm_rf
touch(list, noop: nil, verbose: nil, mtime: nil, nocreate: nil) 点击切换源代码

更新list(单个路径或路径数组)中路径所指定条目的修改时间 (mtime) 和访问时间 (atime);如果它是一个数组,则返回list,否则返回[list]

默认情况下,将为任何不存在的条目路径创建一个空文件;使用关键字参数nocreate可以改为引发异常。

参数 list 或其元素应 可解释为路径

示例

# 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'])

关键字参数

  • mtime: time - 将条目的 mtime 设置为给定时间,而不是当前时间。

  • nocreate: true - 如果条目不存在,则引发异常。

  • noop: true - 不触摸条目;返回nil

  • verbose: true - 打印等效命令

    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)
    

    输出

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

相关:FileUtils.uptodate?

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

如果路径new处的文件比数组old_list中所有路径处的文件都新,则返回true;否则返回false

参数newold_list的元素应可解释为路径

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

不存在的文件被认为是无限旧的。

相关:FileUtils.touch

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