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
.
我在 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
.