bash 流上的多行字符串替换

Multiline string substitution on bash stream

我在 GCS 中有一个大型 (>500GB) Postgres 转储,我想从中删除 COPY 命令。鉴于转储的大小,我想在 gsutil cat 流上执行替换而不是在本地存储:

gsutil cat gs://mybucket.mydomain.com/path/to/mydump.sql | some_command > mydump-commands.sql

COPY 命令可以跨越多行,但始终以 \. 结尾。

我试过 perl:

# some_command = 
perl -pe 'BEGIN{undef $/;} s/COPY.*\.//smg'

这适用于一个小样本本地文件(如下),但似乎不适用于从 stdin 流式传输。

--
-- PostgreSQL database dump
--

-- Dumped from database version 14.1
-- Dumped by pg_dump version 14.1

SET statement_timeout = 0;
SET lock_timeout = 0;
SET idle_in_transaction_session_timeout = 0;
SET client_encoding = 'UTF8';
SET standard_conforming_strings = on;
SELECT pg_catalog.set_config('search_path', '', false);
SET check_function_bodies = false;
SET xmloption = content;
SET client_min_messages = warning;
SET row_security = off;

SET default_tablespace = '';

SET default_table_access_method = heap;

--
-- Name: mytable; Type: TABLE; Schema: dummy; Owner: bchrobot
--

CREATE TABLE dummy.mytable (
    id integer,
    title text
);


ALTER TABLE dummy.mytable OWNER TO bchrobot;

--
-- Data for Name: mytable; Type: TABLE DATA; Schema: dummy; Owner: bchrobot
--

COPY dummy.mytable (id, title) FROM stdin;
1   my first title
2   my second title
\.


--
-- PostgreSQL database dump complete
--

对此有什么建议,特别是在处理流方面?

首先,你还需要避开句号\.。由于您有一些开始 ^ 和行尾 $ 限制,因此您也应该添加这些限制。

由于您正在流式传输输入,因此您不能 undef $/ 否则它会尝试将所有 500Gb 读入内存,您的程序可能会挂起。您必须逐行阅读。

您可以尝试 flip-flop operator:

perl -ne'print unless /^COPY/ ... /^\\.$/' psql.txt

如果 LHS 模式匹配为真,则范围运算符 ...(或 ..)将为真,并且对于之后的每一行,直到并包括当 RHS 模式为真时。否则为假。

因此我们打印所有未包含在该段落中的行。

这个 sed 命令,作为 some_command 的替代,将删除以 COPY 开头的行和由 \. 组成的行之间的所有行,包括那些两行。

sed '/^COPY/,/^\\.$/d'

只需使用 pg_dump--schema-only 选项,

--schema-only Dump only the object definitions (schema), not data. This option is the inverse of --data-only. It is similar to, but for historical reasons not identical to, specifying --section=pre-data --section=post-data.