有没有办法列出文件夹中的文件?
类似的东西:
select * from pg_ls_dir('/home/christian')
我尝试了pg_ls_dir
,但per documentation:
仅数据库群集目录中的文件和
log_directory
可以访问。使用群集中文件的相对路径 目录,以及与log_directory
配置设置匹配的路径 用于日志文件。这些功能的使用仅限于超级用户。
我需要列出postgres目录之外的文件夹中的文件,类似于COPY
完成的文件。
答案 0 :(得分:9)
使用PostgreSQL 9.3,可以避免安装语言扩展的开销:
DROP TABLE IF EXISTS files;
CREATE TABLE files(filename text);
COPY files FROM PROGRAM 'find /usr/bin -maxdepth 1 -type f -printf "%f\n"';
SELECT * FROM files ORDER BY filename ASC;
在我的计算机上,从[
到zip
在81毫秒内创建一个包含2,000多行的表格。
通常COPY
命令需要超级用户权限。由于文件系统的路径是硬编码的(即,不是来自用户的未经过计算的值),因此首先使用超级用户帐户定义函数不会带来很大的安全风险(例如, postgres
)如下:
CREATE OR REPLACE FUNCTION files()
RETURNS SETOF text AS
$BODY$
BEGIN
SET client_min_messages TO WARNING;
DROP TABLE IF EXISTS files;
CREATE TEMP TABLE files(filename text);
COPY files FROM PROGRAM 'find /usr/bin -maxdepth 1 -type f -printf "%f\n"';
RETURN QUERY SELECT * FROM files ORDER BY filename ASC;
END;
$BODY$
LANGUAGE plpgsql SECURITY DEFINER;
使用非超级用户帐户登录PostgreSQL,然后:
SELECT * FROM files();
应返回相同的结果列表,不会出现任何安全违规错误。
SECURITY DEFINER
告诉PostgreSQL在用于创建函数的帐户的角色下运行该函数。由于它是使用超级用户角色创建的,因此无论执行命令的角色如何,它都将以超级用户权限执行。
如果无法删除表,SET client_min_messages TO WARNING;
告诉PostgreSQL禁止消息。删除这一行是可以的。
CREATE TEMP TABLE
用于创建一个不需要随时间持续存在的表。如果您需要永久表,请删除TEMP
修饰符。
'find...'
命令(也可以是/usr/bin/find
)仅列出文件(type -f
)并仅显示文件名,而前导路径每行只分隔一个文件名({{1} })。最后,-printf "%f\n"
将文件搜索限制为仅指定的目录,而不搜索任何子目录。有关详细信息,请参阅find's man page。
这种方法的一个缺点是似乎没有办法参数化要执行的命令。似乎PostgreSQL要求它是文本字符串,而不是表达式语句。也许这是最好的,因为它阻止允许执行任意命令。你看到的就是你执行的东西。
答案 1 :(得分:5)
它通常对SQL客户端没用。
无论如何,您需要实现它,这是plperlu
等脚本语言的典型用例。例如:
CREATE FUNCTION nosecurity_ls(text) RETURNS setof text AS $$
opendir(my $d, $_[0]) or die $!;
while (my $f=readdir($d)) {
return_next($f);
}
return undef;
$$ language plperlu;
除了限制之外,它等同于System Administration Functions中提到的pg_ls_dir(text)
功能。
=> select * from nosecurity_ls('/var/lib/postgresql/9.1/main') as ls;
ls ----------------- pg_subtrans pg_serial pg_notify pg_clog pg_multixact .. base pg_twophase etc...
答案 2 :(得分:5)
this answer的扩展版本,功能ls_files_extended:
-- Unfortunately that variant only allow use hardcoded path
-- To use user parameter we will use dynamic EXECUTE.
-- Return also file size and allow filtering
--
-- @param path text. Filesystem path for read to
-- @param filter text (default null meaning return all). Where condition to filter files. F.e.: $$filename LIKE '0%'$$
-- @param sort text (default filename).
--
-- Examples of use:
-- 1) Simple call, return all files, sort by filename:
-- SELECT * FROM ls_files_extended('/pg_xlog.archive')
-- 2) Return all, sort by filesize:
-- SELECT * FROM ls_files_extended('/pg_xlog.archive', null, 'size ASC')
-- 3) Use filtering and sorting:
-- SELECT * FROM ls_files_extended('/pg_xlog.archive', 'filename LIKE ''0%''', 'size ASC')
-- or use $-quoting for easy readability:
-- SELECT * FROM ls_files_extended('/pg_xlog.archive', $$filename LIKE '0%'$$, 'size ASC')
CREATE OR REPLACE FUNCTION ls_files_extended(path text, filter text default null, sort text default 'filename')
RETURNS TABLE(filename text, size bigint) AS
$BODY$
BEGIN
SET client_min_messages TO WARNING;
CREATE TEMP TABLE _files(filename text, size bigint) ON COMMIT DROP;
EXECUTE format($$COPY _files FROM PROGRAM 'find %s -maxdepth 1 -type f -printf "%%f\t%%s\n"'$$, path);
RETURN QUERY EXECUTE format($$SELECT * FROM _files WHERE %s ORDER BY %s $$, concat_ws(' AND ', 'true', filter), sort);
END;
$BODY$ LANGUAGE plpgsql SECURITY DEFINER;