我想做的是将数据库表数据的子集从 X 环境复制到本地文件存储。 我尝试使用 Java 运行时执行 psql 命令,但失败了
this.psqlExportDataFile = "psql postgresql://dburl -o /Users/Shared/CopyDB/project.csv -c \"COPY (SELECT * FROM gls.project where id in (112371,148904,1652068)) TO STDOUT(FORMAT csv, DELIMITER ',', NULL 'null')'\"";
Process process = runtime.exec(psqlExportDataFile);
System.out.println(new String(toByteArray(process.getErrorStream())));
但是当我在 shell 中运行它时它通常可以工作。
错误输出为:
ERROR: unterminated quoted identifier at or near ""COPY"
LINE 1: "COPY
^
可能是什么问题?
您错误地认为“在命令行上键入”(
cmd.exe
,或/bin/bash
,或任何您的终端)与“启动进程”相同。不是这样的。
你的 shell 可以做很多事情。它采用您输入的字符串并以多种方式处理它。当然,它会导致运行一个命令(在这里,启动
psql.exe
或 /bin/psql
或诸如此类的东西,并将某些参数传递给该进程)。但这是 bash
/ cmd.exe
例如应用引号、空间分割以及所有爵士乐。
Java 的进程构建器不是
cmd.exe
,也不是 /bin/bash
。除了空间分割之外,它几乎没有任何作用。你想控制它,所以停止使用 Runtime.exec()
并使用 ProcessBuilder
来代替,整个“围绕参数的引用”并不是 ProcessBuilder 的工作方式。 bash/cmd 决定:要传递超过 1 个参数,请在它们之间放置空格,然后解决“如果我想传递一个本身包含空格的单个参数怎么办”的困境:“啊,好吧,那么,嗯,用引号引起来吗?”。
Java 的 processbuilder 选择了一个不同的、更简单的解决方案:将每个参数传递为.. 1 个参数:
new ProcessBuilder(
"/bin/psql",
"postgresql://dburl",
"-o",
"/Users/Shared/CopyDB/project.csv",
"-c",
"COPY (SELECT * FROM gls.project where id in (112371,148904,1652068)) TO STDOUT(FORMAT csv, DELIMITER ',', NULL 'null');");
然后运行/