You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何在Godot 4.6跨平台环境下向fzf --filter传递stdin输入?

在Godot 4.6中跨平台向fzf --filter通过stdin传递大量文件列表

要解决跨平台下给fzf --filter传递大量文件列表的问题,核心方案是使用OS.execute_with_pipe——它支持通过管道向子进程的stdin写入数据,同时读取stdout的结果,既没有输入长度限制,也能兼容Windows、Mac和Linux。

完整实现代码

下面是封装好的工具函数,包含文件遍历、fzf调用、结果读取的完整流程:

# 用fzf筛选文件列表,返回匹配的文件路径数组
func filter_files_with_fzf(filter_query: String, file_list: Array[String]) -> Array[String]:
    # 初始化管道对应的文件访问对象
    var stdin = FileAccess.new()
    var stdout = FileAccess.new()
    var stderr = FileAccess.new()

    # 启动fzf进程,传入过滤参数
    var pid = OS.execute_with_pipe("fzf", ["--filter", filter_query], stdin, stdout, stderr)
    
    if pid == -1:
        print_err("无法启动fzf,请确认fzf已安装并添加到系统PATH")
        return []

    # 向fzf的stdin写入文件列表(每行一个文件)
    stdin.open_from_fd(stdin.get_fd(), FileAccess.WRITE)
    for file_path in file_list:
        stdin.print_line(file_path)
    stdin.close()  # 关闭stdin,告知fzf输入结束

    # 读取fzf的stdout结果
    stdout.open_from_fd(stdout.get_fd(), FileAccess.READ)
    var filtered_results = []
    while not stdout.eof_reached():
        var line = stdout.get_line().strip_edges()
        if line != "":
            filtered_results.append(line)
    stdout.close()

    # 读取错误输出(可选,用于调试)
    stderr.open_from_fd(stderr.get_fd(), FileAccess.READ)
    var err_msg = stderr.get_as_text()
    stderr.close()
    if err_msg != "":
        print_warn("fzf错误输出: ", err_msg)

    # 等待进程结束并检查退出状态
    var exit_code = OS.wait_for_process(pid)
    if exit_code != 0:
        print_warn("fzf异常退出,代码: ", exit_code)

    return filtered_results

# 跨平台遍历目录,获取所有文件的路径数组
func get_all_files(directory: String) -> Array[String]:
    var files = []
    var dir = DirAccess.open(directory)
    if dir == null:
        print_err("无法打开目录: ", directory)
        return files

    dir.list_dir_begin(true, true)  # 递归遍历、包含隐藏文件
    var file_name = dir.get_next()
    while file_name != "":
        if dir.current_is_dir():
            files += get_all_files(directory + "/" + file_name)
        else:
            files.append(directory + "/" + file_name)
        file_name = dir.get_next()
    dir.list_dir_end()
    return files

使用示例

在你的脚本中直接调用上述函数即可:

func _ready():
    # 获取当前目录下所有文件
    var all_files = get_all_files(".")
    # 用fzf筛选包含"hi"的文件
    var matched_files = filter_files_with_fzf("hi", all_files)
    print("筛选结果: ", matched_files)

关键注意事项

  1. fzf环境准备:确保fzf已安装并添加到系统PATH中——Windows可直接下载fzf.exe放入PATH目录,Mac用brew install fzf,Linux用包管理器安装。
  2. 管道操作细节:必须手动关闭stdin,否则fzf会一直等待输入,进程无法结束。
  3. 跨平台兼容性:用Godot原生的DirAccess遍历目录,替代依赖shell的find命令,确保Windows、Mac、Linux都能正常运行。
  4. 无长度限制:相比shell的<<<输入方式,管道写入没有数据长度限制,支持超大规模文件列表。

内容的提问来源于stack exchange,提问作者jakub

火山引擎 最新活动