模块 Bundler::FileUtils

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

此处内容

首先,了解其他地方的内容。模块 Bundler::FileUtils

  • 继承自类 Object

  • 补充了 File 类(但未包含或扩展到该类中)。

在这里,模块 Bundler::FileUtils 提供了用于以下目的的方法:

创建

删除

查询

  • ::pwd::getwd:返回工作目录的路径。

  • ::uptodate?:返回给定条目是否比给定的其他条目更新。

设置

  • ::cd::chdir:设置工作目录。

  • ::chmod:设置条目的权限。

  • ::chmod_R:设置条目及其后代的权限。

  • ::chown:设置条目的所有者和组。

  • ::chown_R:设置条目及其后代的所有者和组。

  • ::touch:设置条目的修改和访问时间,并在必要时创建。

比较

复制

移动

选项

路径参数

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

  • 如果参数是字符串,则该值是路径。

  • 如果参数具有方法 :to_path,则通过该方法转换。

  • 如果参数具有方法 :to_str,则通过该方法转换。

关于示例

此处的一些示例涉及文件条目的树。对于这些示例,我们有时使用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 的潜在漏洞,当以下情况时可能会出现该漏洞:

  • 目标路径上条目的祖先目录是全局可写的;此类目录包括 /tmp

  • 目标路径上的目录树包括

    • 全局可写的后代目录。

    • 符号链接。

为了避免该漏洞,您可以使用此方法删除条目

以下方法也可用,每个方法都调用 Bundler::FileUtils.remove_entry_secure

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

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

  • 如果目标路径指向目录,则此方法在删除目录时使用 File#chown 和 File#chmod 方法。

  • 目标目录的所有者应该是当前进程或超级用户(root)。

警告:您必须确保所有父目录都不能被其他不受信任的用户移动。例如,父目录不应由不受信任的用户拥有,并且除非设置了粘滞位,否则不应全局可写。

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

常量

VERSION

版本号。

公共类方法

cd(dir, verbose: nil) { |dir| ... } 点击切换源代码

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

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

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

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

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

关键字参数

  • verbose: true - 打印等效的命令

    Bundler::FileUtils.cd('..')
    Bundler::FileUtils.cd('fileutils')
    

    输出

    cd ..
    cd fileutils

相关:Bundler::FileUtils.pwd

# File bundler/vendor/fileutils/lib/fileutils.rb, line 239
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:表示要设置的权限位

    Bundler::FileUtils.chmod(0755, 'src0.txt')
    Bundler::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 位。

    示例

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

关键字参数

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

  • verbose: true - 打印等效的命令

    Bundler::FileUtils.chmod(0755, 'src0.txt', noop: true, verbose: true)
    Bundler::FileUtils.chmod(0644, ['src0.txt', 'src0.dat'], noop: true, verbose: true)
    Bundler::FileUtils.chmod('u=wrx,go=rx', 'src1.txt', noop: true, verbose: true)
    Bundler::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

相关:Bundler::FileUtils.chmod_R

# File bundler/vendor/fileutils/lib/fileutils.rb, line 1804
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) 点击切换源代码

类似于 Bundler::FileUtils.chmod,但会递归地更改权限。

# File bundler/vendor/fileutils/lib/fileutils.rb, line 1816
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,否则返回 [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
Bundler::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.
Bundler::FileUtils.chown(1004, 1004, 'src0.txt')
File.stat('src0.txt').uid # => 1004
File.stat('src0.txt').gid # => 1004

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

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

关键字参数

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

  • verbose: true - 打印等效的命令

    Bundler::FileUtils.chown('user2', 'group1', 'src0.txt', noop: true, verbose: true)
    Bundler::FileUtils.chown(1004, 1004, 'src0.txt', noop: true, verbose: true)
    Bundler::FileUtils.chown(1006, 1005, ['src0.txt', 'src0.dat'], noop: true, verbose: true)
    Bundler::FileUtils.chown('user2', 'group1', path, noop: true, verbose: true)
    Bundler::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 .

相关:Bundler::FileUtils.chown_R

# File bundler/vendor/fileutils/lib/fileutils.rb, line 1897
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) 点击切换源代码

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

# File bundler/vendor/fileutils/lib/fileutils.rb, line 1913
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;参数必须是符号

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

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

Bundler::FileUtils.commands.sort.take(3) # => ["cd", "chdir", "chmod"]
# File bundler/vendor/fileutils/lib/fileutils.rb, line 2572
def self.commands
  OPT_TABLE.keys
end
compare_file(a, b) 点击切换源代码

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

参数 ab 应该可解释为路径

Bundler::FileUtils.identical?Bundler::FileUtils.cmpBundler::FileUtils.compare_file 的别名。

相关:Bundler::FileUtils.compare_stream

# File bundler/vendor/fileutils/lib/fileutils.rb, line 1508
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 应该可解释为路径

相关:Bundler::FileUtils.compare_file

# File bundler/vendor/fileutils/lib/fileutils.rb, line 1531
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

Bundler::FileUtils.touch('src0.txt')
File.exist?('dest0.txt') # => false
Bundler::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
Bundler::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 bundler/vendor/fileutils/lib/fileutils.rb, line 1041
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 应该可解释为路径

示例

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

关键字参数

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

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

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

相关:复制方法

# File bundler/vendor/fileutils/lib/fileutils.rb, line 1077
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 bundler/vendor/fileutils/lib/fileutils.rb, line 1089
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

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

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

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

如果 src 是文件路径数组,并且 dest 是目录的路径,则将每个 src 复制到 dest

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

关键字参数

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

  • noop: true - 不复制文件。

  • verbose: true - 打印等效的命令

    Bundler::FileUtils.cp('src0.txt', 'dest0.txt', noop: true, verbose: true)
    Bundler::FileUtils.cp('src1.txt', 'dest1', noop: true, verbose: true)
    Bundler::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 bundler/vendor/fileutils/lib/fileutils.rb, line 874
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
Bundler::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
Bundler::FileUtils.mkdir('dest1')
Bundler::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
Bundler::FileUtils.mkdir('dest2')
Bundler::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 - 打印等效的命令

    Bundler::FileUtils.cp_lr('src0', 'dest0', noop: true, verbose: true)
    Bundler::FileUtils.cp_lr('src1', 'dest1', noop: true, verbose: true)
    Bundler::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 bundler/vendor/fileutils/lib/fileutils.rb, line 628
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 (单个路径)应该可解释为路径

在副本中保留模式、所有者和组;要更改这些内容,请改用 Bundler::FileUtils.install

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

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

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

Bundler::FileUtils.touch('src1.txt')
Bundler::FileUtils.mkdir('dest1')
Bundler::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
Bundler::FileUtils.exist?('dest2') # => false
Bundler::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
Bundler::FileUtils.mkdir('dest3')
Bundler::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 - 打印等效的命令

    Bundler::FileUtils.cp_r('src0.txt', 'dest0.txt', noop: true, verbose: true)
    Bundler::FileUtils.cp_r('src1.txt', 'dest1', noop: true, verbose: true)
    Bundler::FileUtils.cp_r('src2', 'dest2', noop: true, verbose: true)
    Bundler::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 bundler/vendor/fileutils/lib/fileutils.rb, line 986
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;参数可以是字符串或符号

Bundler::FileUtils.have_option?(:chmod, :noop) # => true
Bundler::FileUtils.have_option?('chmod', 'secure') # => false
# File bundler/vendor/fileutils/lib/fileutils.rb, line 2590
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
Bundler::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"
Bundler::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"
Bundler::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
Bundler::FileUtils.mkdir('dest3')
Bundler::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 - 打印等效的命令

    Bundler::FileUtils.install('src0.txt', 'dest0.txt', noop: true, verbose: true)
    Bundler::FileUtils.install('src1.txt', 'dest1.txt', noop: true, verbose: true)
    Bundler::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 bundler/vendor/fileutils/lib/fileutils.rb, line 1610
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 的硬链接。

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

如果 src 是一个目录路径,且 dest 不存在,则在 dest 递归地创建指向 src 中路径的硬链接。

Bundler::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',
  ]
Bundler::FileUtils.touch(src_file_paths)
File.directory?('dest1')        # => true
Bundler::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,则引发异常。

相关方法: Bundler::FileUtils.ln (具有不同的选项)。

# File bundler/vendor/fileutils/lib/fileutils.rb, line 813
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/')                    # => []
Bundler::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')               # => []
Bundler::FileUtils.ln('tmp2/t.dat', 'tmp3') # => 0
Dir.children('tmp3')               # => ["t.dat"]

src 是一个已存在的文件路径数组,且 dest 是一个已存在的目录路径时,则对于 src 中的每个路径 target,会在 dest/target 创建一个指向 target 的硬链接;返回 src

Dir.children('tmp4/')                               # => []
Bundler::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 - 打印等效的命令

    Bundler::FileUtils.ln('tmp0/t.txt', 'tmp1/t.lnk', verbose: true)
    Bundler::FileUtils.ln('tmp2/t.dat', 'tmp3', verbose: true)
    Bundler::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,则会引发异常。

相关方法: Bundler::FileUtils.link_entry (具有不同的选项)。

# File bundler/vendor/fileutils/lib/fileutils.rb, line 517
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 的符号链接。

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

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

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

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

如果 src 是一个已存在的文件路径数组,且 dest 是一个目录,则对于 src 中的每个子项 child,会创建符号链接 dest/child 指向 child

Bundler::FileUtils.mkdir('srcdir3')
Bundler::FileUtils.touch('srcdir3/src0.txt')
Bundler::FileUtils.touch('srcdir3/src1.txt')
Bundler::FileUtils.mkdir('destdir3')
Bundler::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 - 打印等效的命令

    Bundler::FileUtils.ln_s('src0.txt', 'dest0.txt', noop: true, verbose: true)
    Bundler::FileUtils.ln_s('src1.txt', 'destdir1', noop: true, verbose: true)
    Bundler::FileUtils.ln_s('src2.txt', 'dest2.txt', force: true, noop: true, verbose: true)
    Bundler::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

相关方法: Bundler::FileUtils.ln_sf

# File bundler/vendor/fileutils/lib/fileutils.rb, line 707
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) 点击切换源代码

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

# File bundler/vendor/fileutils/lib/fileutils.rb, line 725
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) 点击切换源代码

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

# File bundler/vendor/fileutils/lib/fileutils.rb, line 732
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 或其元素应解释为路径

如果没有关键字参数,则通过调用 Dir.mkdir(path, mode)list 中的每个 path 上创建一个目录;请参阅 Dir.mkdir。

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

关键字参数

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

  • noop: true - 不创建目录。

  • verbose: true - 打印等效的命令

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

    输出

    mkdir tmp0 tmp1
    mkdir -m 700 tmp2 tmp3

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

相关方法: Bundler::FileUtils.mkdir_p

# File bundler/vendor/fileutils/lib/fileutils.rb, line 317
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 或其元素应解释为路径

如果没有关键字参数,则通过调用 Dir.mkdir(path, mode)list 中的每个 path 上创建一个目录,以及任何需要的祖先目录;请参阅 Dir.mkdir。

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

关键字参数

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

  • noop: true - 不创建目录。

  • verbose: true - 打印等效的命令

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

    输出

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

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

Bundler::FileUtils.mkpathBundler::FileUtils.makedirsBundler::FileUtils.mkdir_p 的别名。

相关方法: Bundler::FileUtils.mkdir

# File bundler/vendor/fileutils/lib/fileutils.rb, line 366
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
别名为: mkpath, makedirs
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
Bundler::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
Bundler::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;有关详细信息,请参阅 Bundler::FileUtils.remove_entry_secure

  • verbose: true - 打印等效的命令

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

    输出

    mv src0 dest0
    mv src1.txt src1 dest1
    
# File bundler/vendor/fileutils/lib/fileutils.rb, line 1158
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() 点击切换源代码

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

Bundler::FileUtils.options.take(3) # => ["noop", "verbose", "force"]
# File bundler/vendor/fileutils/lib/fileutils.rb, line 2580
def self.options
  OPT_TABLE.values.flatten.uniq.map {|sym| sym.to_s }
end
options_of(mid) 点击切换源代码

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

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

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

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

相关方法: Bundler::FileUtils.cd

# File bundler/vendor/fileutils/lib/fileutils.rb, line 198
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 bundler/vendor/fileutils/lib/fileutils.rb, line 1493
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 及其子类的异常。

相关方法: Bundler::FileUtils.remove_entry_secure

# File bundler/vendor/fileutils/lib/fileutils.rb, line 1450
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 bundler/vendor/fileutils/lib/fileutils.rb, line 1352
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, Bundler::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 bundler/vendor/fileutils/lib/fileutils.rb, line 1474
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 中给定路径的文件。

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

关键字参数

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

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

  • verbose: true - 打印等效的命令

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

    输出

    rm src0.dat src0.txt
    

相关方法: 用于删除的方法

# File bundler/vendor/fileutils/lib/fileutils.rb, line 1217
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) 点击切换源代码

等效于

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

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

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

相关方法: 用于删除的方法

# File bundler/vendor/fileutils/lib/fileutils.rb, line 1242
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]

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

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

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

Bundler::FileUtils.touch(['src0.txt', 'src0.dat'])
Bundler::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
Bundler::FileUtils.rm_r('src1')
File.exist?('src1') # => false

关键字参数

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

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

  • secure: true - 安全地删除 src;有关详细信息,请参阅 Bundler::FileUtils.remove_entry_secure

  • verbose: true - 打印等效的命令

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

    输出

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

相关方法: 用于删除的方法

# File bundler/vendor/fileutils/lib/fileutils.rb, line 1300
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) 点击以切换源代码

等效于

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

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

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

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

相关方法: 用于删除的方法

# File bundler/vendor/fileutils/lib/fileutils.rb, line 1329
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]

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

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

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

关键字参数

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

  • noop: true - 不删除目录。

  • verbose: true - 打印等效的命令

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

    输出

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

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

相关方法: 用于删除的方法

# File bundler/vendor/fileutils/lib/fileutils.rb, line 443
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,否则返回 [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
Bundler::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.
Bundler::FileUtils.touch(['src0.txt', 'src0.dat'])

关键字参数

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

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

  • noop: true - 不修改条目;返回 nil

  • verbose: true - 打印等效的命令

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

    输出

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

相关: Bundler::FileUtils.uptodate?

# File bundler/vendor/fileutils/lib/fileutils.rb, line 2007
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 的元素应该是 可解释为路径 的。

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

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

相关: Bundler::FileUtils.touch

# File bundler/vendor/fileutils/lib/fileutils.rb, line 265
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解释为路径

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

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

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

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

关键字参数

  • verbose: true - 打印等效的命令

    Bundler::FileUtils.cd('..')
    Bundler::FileUtils.cd('fileutils')
    

    输出

    cd ..
    cd fileutils

相关:Bundler::FileUtils.pwd

# File bundler/vendor/fileutils/lib/fileutils.rb, line 239
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:表示要设置的权限位

    Bundler::FileUtils.chmod(0755, 'src0.txt')
    Bundler::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 位。

    示例

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

关键字参数

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

  • verbose: true - 打印等效的命令

    Bundler::FileUtils.chmod(0755, 'src0.txt', noop: true, verbose: true)
    Bundler::FileUtils.chmod(0644, ['src0.txt', 'src0.dat'], noop: true, verbose: true)
    Bundler::FileUtils.chmod('u=wrx,go=rx', 'src1.txt', noop: true, verbose: true)
    Bundler::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

相关:Bundler::FileUtils.chmod_R

# File bundler/vendor/fileutils/lib/fileutils.rb, line 1804
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) 点击切换源代码

类似于 Bundler::FileUtils.chmod,但会递归地更改权限。

# File bundler/vendor/fileutils/lib/fileutils.rb, line 1816
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,否则返回 [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
Bundler::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.
Bundler::FileUtils.chown(1004, 1004, 'src0.txt')
File.stat('src0.txt').uid # => 1004
File.stat('src0.txt').gid # => 1004

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

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

关键字参数

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

  • verbose: true - 打印等效的命令

    Bundler::FileUtils.chown('user2', 'group1', 'src0.txt', noop: true, verbose: true)
    Bundler::FileUtils.chown(1004, 1004, 'src0.txt', noop: true, verbose: true)
    Bundler::FileUtils.chown(1006, 1005, ['src0.txt', 'src0.dat'], noop: true, verbose: true)
    Bundler::FileUtils.chown('user2', 'group1', path, noop: true, verbose: true)
    Bundler::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 .

相关:Bundler::FileUtils.chown_R

# File bundler/vendor/fileutils/lib/fileutils.rb, line 1897
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) 点击切换源代码

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

# File bundler/vendor/fileutils/lib/fileutils.rb, line 1913
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 应该可解释为路径

Bundler::FileUtils.identical?Bundler::FileUtils.cmpBundler::FileUtils.compare_file 的别名。

相关:Bundler::FileUtils.compare_stream

# File bundler/vendor/fileutils/lib/fileutils.rb, line 1508
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 应该可解释为路径

相关:Bundler::FileUtils.compare_file

# File bundler/vendor/fileutils/lib/fileutils.rb, line 1531
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

Bundler::FileUtils.touch('src0.txt')
File.exist?('dest0.txt') # => false
Bundler::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
Bundler::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 bundler/vendor/fileutils/lib/fileutils.rb, line 1041
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 应该可解释为路径

示例

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

关键字参数

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

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

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

相关:复制方法

# File bundler/vendor/fileutils/lib/fileutils.rb, line 1077
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 bundler/vendor/fileutils/lib/fileutils.rb, line 1089
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

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

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

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

如果 src 是文件路径数组,并且 dest 是目录的路径,则将每个 src 复制到 dest

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

关键字参数

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

  • noop: true - 不复制文件。

  • verbose: true - 打印等效的命令

    Bundler::FileUtils.cp('src0.txt', 'dest0.txt', noop: true, verbose: true)
    Bundler::FileUtils.cp('src1.txt', 'dest1', noop: true, verbose: true)
    Bundler::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 bundler/vendor/fileutils/lib/fileutils.rb, line 874
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
Bundler::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
Bundler::FileUtils.mkdir('dest1')
Bundler::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
Bundler::FileUtils.mkdir('dest2')
Bundler::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 - 打印等效的命令

    Bundler::FileUtils.cp_lr('src0', 'dest0', noop: true, verbose: true)
    Bundler::FileUtils.cp_lr('src1', 'dest1', noop: true, verbose: true)
    Bundler::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 bundler/vendor/fileutils/lib/fileutils.rb, line 628
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 (单个路径)应该可解释为路径

在副本中保留模式、所有者和组;要更改这些内容,请改用 Bundler::FileUtils.install

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

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

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

Bundler::FileUtils.touch('src1.txt')
Bundler::FileUtils.mkdir('dest1')
Bundler::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
Bundler::FileUtils.exist?('dest2') # => false
Bundler::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
Bundler::FileUtils.mkdir('dest3')
Bundler::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 - 打印等效的命令

    Bundler::FileUtils.cp_r('src0.txt', 'dest0.txt', noop: true, verbose: true)
    Bundler::FileUtils.cp_r('src1.txt', 'dest1', noop: true, verbose: true)
    Bundler::FileUtils.cp_r('src2', 'dest2', noop: true, verbose: true)
    Bundler::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 bundler/vendor/fileutils/lib/fileutils.rb, line 986
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 的别名
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
Bundler::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"
Bundler::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"
Bundler::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
Bundler::FileUtils.mkdir('dest3')
Bundler::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 - 打印等效的命令

    Bundler::FileUtils.install('src0.txt', 'dest0.txt', noop: true, verbose: true)
    Bundler::FileUtils.install('src1.txt', 'dest1.txt', noop: true, verbose: true)
    Bundler::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 bundler/vendor/fileutils/lib/fileutils.rb, line 1610
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 的硬链接。

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

如果 src 是一个目录路径,且 dest 不存在,则在 dest 递归地创建指向 src 中路径的硬链接。

Bundler::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',
  ]
Bundler::FileUtils.touch(src_file_paths)
File.directory?('dest1')        # => true
Bundler::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,则引发异常。

相关方法: Bundler::FileUtils.ln (具有不同的选项)。

# File bundler/vendor/fileutils/lib/fileutils.rb, line 813
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/')                    # => []
Bundler::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')               # => []
Bundler::FileUtils.ln('tmp2/t.dat', 'tmp3') # => 0
Dir.children('tmp3')               # => ["t.dat"]

src 是一个已存在的文件路径数组,且 dest 是一个已存在的目录路径时,则对于 src 中的每个路径 target,会在 dest/target 创建一个指向 target 的硬链接;返回 src

Dir.children('tmp4/')                               # => []
Bundler::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 - 打印等效的命令

    Bundler::FileUtils.ln('tmp0/t.txt', 'tmp1/t.lnk', verbose: true)
    Bundler::FileUtils.ln('tmp2/t.dat', 'tmp3', verbose: true)
    Bundler::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,则会引发异常。

相关方法: Bundler::FileUtils.link_entry (具有不同的选项)。

# File bundler/vendor/fileutils/lib/fileutils.rb, line 517
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 的符号链接。

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

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

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

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

如果 src 是一个已存在的文件路径数组,且 dest 是一个目录,则对于 src 中的每个子项 child,会创建符号链接 dest/child 指向 child

Bundler::FileUtils.mkdir('srcdir3')
Bundler::FileUtils.touch('srcdir3/src0.txt')
Bundler::FileUtils.touch('srcdir3/src1.txt')
Bundler::FileUtils.mkdir('destdir3')
Bundler::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 - 打印等效的命令

    Bundler::FileUtils.ln_s('src0.txt', 'dest0.txt', noop: true, verbose: true)
    Bundler::FileUtils.ln_s('src1.txt', 'destdir1', noop: true, verbose: true)
    Bundler::FileUtils.ln_s('src2.txt', 'dest2.txt', force: true, noop: true, verbose: true)
    Bundler::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

相关方法: Bundler::FileUtils.ln_sf

# File bundler/vendor/fileutils/lib/fileutils.rb, line 707
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) 点击切换源代码

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

# File bundler/vendor/fileutils/lib/fileutils.rb, line 725
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) 点击切换源代码

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

# File bundler/vendor/fileutils/lib/fileutils.rb, line 732
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 或其元素应解释为路径

如果没有关键字参数,则通过调用 Dir.mkdir(path, mode)list 中的每个 path 上创建一个目录;请参阅 Dir.mkdir。

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

关键字参数

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

  • noop: true - 不创建目录。

  • verbose: true - 打印等效的命令

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

    输出

    mkdir tmp0 tmp1
    mkdir -m 700 tmp2 tmp3

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

相关方法: Bundler::FileUtils.mkdir_p

# File bundler/vendor/fileutils/lib/fileutils.rb, line 317
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 或其元素应解释为路径

如果没有关键字参数,则通过调用 Dir.mkdir(path, mode)list 中的每个 path 上创建一个目录,以及任何需要的祖先目录;请参阅 Dir.mkdir。

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

关键字参数

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

  • noop: true - 不创建目录。

  • verbose: true - 打印等效的命令

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

    输出

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

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

Bundler::FileUtils.mkpathBundler::FileUtils.makedirsBundler::FileUtils.mkdir_p 的别名。

相关方法: Bundler::FileUtils.mkdir

# File bundler/vendor/fileutils/lib/fileutils.rb, line 366
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
别名为: mkpath, makedirs
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
Bundler::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
Bundler::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;有关详细信息,请参阅 Bundler::FileUtils.remove_entry_secure

  • verbose: true - 打印等效的命令

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

    输出

    mv src0 dest0
    mv src1.txt src1 dest1
    
# File bundler/vendor/fileutils/lib/fileutils.rb, line 1158
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() 点击切换源代码

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

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

相关方法: Bundler::FileUtils.cd

# File bundler/vendor/fileutils/lib/fileutils.rb, line 198
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 bundler/vendor/fileutils/lib/fileutils.rb, line 1493
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 及其子类的异常。

相关方法: Bundler::FileUtils.remove_entry_secure

# File bundler/vendor/fileutils/lib/fileutils.rb, line 1450
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 bundler/vendor/fileutils/lib/fileutils.rb, line 1352
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, Bundler::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 bundler/vendor/fileutils/lib/fileutils.rb, line 1474
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 中给定路径的文件。

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

关键字参数

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

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

  • verbose: true - 打印等效的命令

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

    输出

    rm src0.dat src0.txt
    

相关方法: 用于删除的方法

# File bundler/vendor/fileutils/lib/fileutils.rb, line 1217
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) 点击切换源代码

等效于

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

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

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

相关方法: 用于删除的方法

# File bundler/vendor/fileutils/lib/fileutils.rb, line 1242
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]

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

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

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

Bundler::FileUtils.touch(['src0.txt', 'src0.dat'])
Bundler::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
Bundler::FileUtils.rm_r('src1')
File.exist?('src1') # => false

关键字参数

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

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

  • secure: true - 安全地删除 src;有关详细信息,请参阅 Bundler::FileUtils.remove_entry_secure

  • verbose: true - 打印等效的命令

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

    输出

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

相关方法: 用于删除的方法

# File bundler/vendor/fileutils/lib/fileutils.rb, line 1300
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) 点击以切换源代码

等效于

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

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

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

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

相关方法: 用于删除的方法

# File bundler/vendor/fileutils/lib/fileutils.rb, line 1329
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]

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

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

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

关键字参数

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

  • noop: true - 不删除目录。

  • verbose: true - 打印等效的命令

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

    输出

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

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

相关方法: 用于删除的方法

# File bundler/vendor/fileutils/lib/fileutils.rb, line 443
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,否则返回 [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
Bundler::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.
Bundler::FileUtils.touch(['src0.txt', 'src0.dat'])

关键字参数

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

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

  • noop: true - 不修改条目;返回 nil

  • verbose: true - 打印等效的命令

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

    输出

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

相关: Bundler::FileUtils.uptodate?

# File bundler/vendor/fileutils/lib/fileutils.rb, line 2007
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 的元素应该是 可解释为路径 的。

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

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

相关: Bundler::FileUtils.touch

# File bundler/vendor/fileutils/lib/fileutils.rb, line 265
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