如何让 Postgres DO $$ 在 bash 提示符下工作?

Ron*_*ohn 1 postgresql scripting postgresql-9.6

Linux RHEL 6.10 上的 Postgres 9.6.9

如果我将 DO 命令用双引号括起来,角色用单引号括起来,那么 bash 会解释$$,这显然会使命令失败。所以我切换了双引号和单引号,但现在它将NOT IN字符串文字视为列名,这也会引发错误。

那么,正如标题中所提到的,DO $$从命令行获取命令的魔力是什么?

$ export PGHOST=10.x.y.z
$ export PGUSER=postgres
$ psql -c 'do $$  
>          declare rolename text;
>          begin
>            for rolename in select rolname 
>                            from pg_roles 
>                            where rolname not in ("postgres",
>                                                  "pg_signal_backend",
>                                                  "TAP")
>            loop
>            execute "DROP ROLE " || rolename;                   
>            end loop;
>          end $$
>          ;'
ERROR:  column "postgres" does not exist
LINE 3:                            where rolname not in ("postgres",...
                                                         ^
QUERY:  select rolname 
                           from pg_roles 
                           where rolname not in ("postgres", "pg_signal_backend", "TAP")
CONTEXT:  PL/pgSQL function inline_code_block line 4 at FOR over SELECT rows
Run Code Online (Sandbox Code Playgroud)

谢谢

Jac*_*cky 5

使用\逃脱美元$

echo \$PATH
$PATH
Run Code Online (Sandbox Code Playgroud)

参考psql doc,为了执行多命令,他们还提供了 3 种解决方法,如下所示

1) 重复-c选项

psql -c 'SELECT now()' -c 'SELECT * FROM foo;'
Run Code Online (Sandbox Code Playgroud)

2) 结合echopsql

echo 'SELECT now() ; SELECT * FROM foo;' | psql
Run Code Online (Sandbox Code Playgroud)

3) 用途psqlEOF

psql <<EOF
\x     
SELECT now(); 
SELECT * FROM foo;
EOF
Run Code Online (Sandbox Code Playgroud)

此外,考虑改变rolename textrolename RECORD以避免ERROR: missing FROM-clause entry for table记录类型

记录变量类似于行类型变量,但它们没有预定义的结构。它们采用在 SELECT 或 FOR 命令期间分配给它们的行的实际行结构

就你的情况而言,DROP ROLE由于依赖关系,请小心(参考:droprole

如果在依赖对象仍然存在的情况下尝试 DROP ROLE,它将发出消息标识哪些对象需要重新分配或删除。

最后但并非最不重要的,这是我的例子

#### Using psql and EOF
psql << EOF
DO \$$
DECLARE
  v_role record; 
BEGIN
  for v_role in select rolname from pg_roles where rolname not in ('postgres', 'pg_signal_backend', 'TAP')
  loop
    raise notice '%', v_role.rolname;
    execute 'DROP ROLE ' || v_role.rolname;  
  end loop;
END
\$$;
EOF

#### Using echo and psql
echo "
DO \$$
DECLARE
  v_role record; 
BEGIN
  for v_role in select rolname from pg_roles where rolname not in ('postgres', 'pg_signal_backend', 'TAP')
  loop
    raise notice '%', v_role.rolname;
    execute 'DROP ROLE ' || v_role.rolname;  
  end loop;
END
\$$;
" | psql 
Run Code Online (Sandbox Code Playgroud)