我该如何非交互地为 'psql' 指定密码?

665

我正在尝试使用shell脚本自动化数据库创建过程,但在将密码传递给psql时遇到了一个障碍。

以下是来自shell脚本的一小段代码:

psql -U $DB_USER -h localhost -c"$DB_RECREATE_SQL"

如何以非交互方式将密码传递给 psql


2
您可以使用连接URL。请在https://dev59.com/bHA65IYBdhLWcg3w4C2j中查看答案。 - paulodiovani
1
@paulodiovani 我只想补充一点,这个命令不需要其他选项 - 只要 psql <连接URL> 谢谢。 - nsandersen
12个回答

1107

在调用psql之前,在脚本中设置PGPASSWORD环境变量。

PGPASSWORD=pass1234 psql -U MyUsername myDatabaseName

参考资料,请参见http://www.postgresql.org/docs/current/static/libpq-envars.html


编辑

自从Postgres 9.2版本以后,还可以使用连接字符串或URI指定用户名密码。语法如下:

$ psql postgresql://[user[:password]@][host][:port][,...][/dbname][?param1=value1&...]

使用该方法存在安全风险,因为通过查看运行进程的命令行(例如使用 ps (Linux)、ProcessExplorer (Windows) 或类似工具),其他用户可以明文看到密码。

也可以参考这个关于数据库管理员问题的讨论。


37
例如,在一行命令中,您可以执行以下操作:PGPASSWORD=pass1234 psql -u MyUsername myUserName - andyortlieb
6
我只能补充 - 在命令行中在第一个字符前添加一个“空格”,这样该命令就不会被存储在bash历史记录中。适用于Ubuntu/Bash。 - baldr
18
额外福利:适用于Docker: docker run -e PGPASSWORD="$(pbpaste)" --rm postgres psql -h www.example.com dbname username -c 'SELECT * FROM table;' - Bilal Akil
4
请注意,在输入命令时一定要加入前导空格,否则该命令会显示在您的bash历史记录~/.bash_history文件中。 - rogerdpack
12
准备使用本指南的用户需知,将密码作为Shell命令的一部分会导致两个问题:1)该密码将在进程列表中显示,并可被系统上所有用户(例如ps -ef)查看;2) 该密码将被添加到您Shell的历史记录文件中(例如.bash_history)。建议将密码存储在一个安全的文件中(例如使用操作系统级别的权限来限制访问),然后运行PGPASSWORD=$(cat /<path>/to/secret.txt) ... - code_dredd
显示剩余9条评论

231

根据官方文档:

为了避免经常输入密码,拥有一个 ~/.pgpass 文件也是很方便的。更多信息请参见第30.13节

...

该文件应包含以下格式的行:

hostname:port:database:username:password

将使用与当前连接参数匹配的第一行密码字段。


51
谢谢,我知道pgpass,但这并不能解决问题——我需要一个自包含的bash脚本来操作数据库,因此我问如何通过命令行将信息传递给psql。 - Alex N.
7
我认为你唯一的选择是设置一个.pgpass文件,让你的bash脚本能够访问。或者干脆不使用密码 - 你可以设置另一种身份验证方式,比如ident或使用SSL证书。 - Jonathan Hall
2
这正是我担心的 :) 感谢提供信息! - Alex N.
另一个选择可能是使用expect。但我真的很讨厌expect :) - Jonathan Hall
请参考下面关于 PGPASSWORD 的注释。虽然可以通过在 /proc 中探测来嗅探它,但它确实运行得非常好,因此安全性可能会有所折扣。 - Steve Byrne
6
别忘了要移除组和其他用户对 .pgpass 文件的读写执行权限!运行 chmod go-rwx .pgpass - Vladislavs Dovgalecs

160
  • 一句话概括:

export PGPASSWORD='password'; psql -h 'server name' -U 'user name' -d 'base name' -c 'command'

使用命令,例如 "select * from schema.table" 的 SQL 命令。

  • 或更易读的:

  • export PGPASSWORD='password'
    psql -h 'server name' -U 'user name' -d 'base name' \
         -c 'command' (eg. "select * from schema.table")
    

    38
    这句话可以稍作简化:PGPASSWORD='password' psql .... 这样做的好处是在命令执行完毕后,该变量便无法被访问。 - Garrett
    3
    export PGPASSWORD=YourNewPassword 对于我来说比其他变化都有效。 - Mikeumus
    19
    “export PGPASSWORD”听起来像一个非常糟糕的主意。 - hasen
    4
    这将会在你的bash历史记录文件~/.bash_history中保存密码(除非你小心地始终在前面加一个空格),并将密码导出到你当前的环境。FWIW :|。 - rogerdpack
    在我的情况下,指定-w标志也起作用了。 - Manuel Lazo
    显示剩余2条评论

    120

    我倾向于将URL传递给psql

    psql "postgresql://$DB_USER:$DB_PWD@$DB_SERVER/$DB_NAME"
    

    这使我有自由地将环境变量命名为我想要的名称,并避免创建不必要的文件。

    这需要使用libpq。文档可以在这里找到。


    你能否在pg_restore中使用类似这样的东西?谢谢! - the_ccalderon
    1
    @ccalderon911217 看起来你可以这样做:https://dev59.com/N14c5IYBdhLWcg3wFm84#28359470 - Jacques Gaudin
    @JacquesGaudin 是的,我已经测试过了!谢谢! - the_ccalderon
    这样,在psql进程运行时,密码将对您机器上的所有用户可见。完整的命令行(包括变量$DB_PWD的解析内容)显示在“ps -ef”或“ps aux”命令中。因此,强烈不建议这样做。 - Holger Jakobs

    52

    在Windows上:

    1. 将值赋给PGPASSWORD: C:\>set PGPASSWORD=pass

    2. 运行命令: C:\>psql -d database -U user

    准备就绪

    或者在一行中:

    set PGPASSWORD=pass&& psql -d database -U user
    

    请注意 && 前面缺少空格!


    1
    我尝试过了,但是没有起作用。仍然要求输入密码。 - antipattern
    3
    你必须同时加上 -w 这个选项。 - mljrg
    1
    PGPASSWORD=xxxx psql -U username -d database -w -c "select * from foo;" 可以正常工作。 - Steve Shipway
    2
    在 Powershell 中,您可以这样做:$env:PGPASSWORD=pass; psql -d database -U user - Venryx
    +1000,关于&&之前没有空格的评论 :) - sur.la.route

    31

    可以通过在(Linux)用户的主目录中创建.pgpass文件来实现。

    .pgpass 文件格式:

    <databaseip>:<port>:<databasename>:<dbusername>:<password>
    

    你也可以使用通配符*代替细节。

    假设我想在不提示密码的情况下运行tmp.sql

    你可以在*.sh文件中使用以下代码。

    echo "192.168.1.1:*:*:postgres:postgrespwd" > $HOME/.pgpass
    echo "` chmod 0600 $HOME/.pgpass `"
    
    echo " ` psql -h 192.168.1.1 -p 5432  -U postgres  postgres  -f tmp.sql `        
    

    15
    回答:「echo "chmod 0600 $HOME/.pgpass"」的意义是将命令输出(echo)到终端上,以便用户确认该命令是否正确执行。而「chmod 0600 $HOME/.pgpass」则是更直接地修改文件权限。 - Vlad Patryshev

    31

    使用PGPASSWORD环境变量的替代方法是根据文档使用conninfo字符串:

    另一种指定连接参数的方法是在conninfo字符串或URI中,该字符串或URI用于替代数据库名称。这种机制可以极大地控制连接。

    $ psql "host=<server> port=5432 dbname=<db> user=<user> password=<password>"
    
    postgres=>
    

    1
    我经常使用这种方法,因为它看起来更易读,但出于安全考虑,在命令中包含密码并不是一个明智的做法,因为任何(非root)用户都可以通过简单的“ps a”命令读取它。 - Marco Carlo Moriggi

    27

    如果现在加入大多数选项还不算太晚:

    有几个选项:

    1. 在pgpass文件中设置。 链接
    1. 设置环境变量并从中获取:

      export PGPASSWORD='password'

      然后运行您的 psql 进行登录,或者甚至从那里运行命令:

      psql -h clustername -U username -d testdb

    2. 在 Windows 上,您需要使用“set” :

      set PGPASSWORD=pass 然后登录到 psql bash。

    3. 通过 URL 和环境变量传递:

      psql "postgresql://$USER_NAME:$PASSWORD@$HOST_NAME/$DB_NAME"


    版本4会使变量$PASSWORD的内容对机器上的所有会话可见。因此,强烈不建议使用。 - Holger Jakobs

    18

    为了更加清晰,补充一下。

    你可以将密码赋值给PGPASSWORD变量。

    所以,取代下面需要你输入密码的方式:

    psql --host=aurora-postgres.cluster-fgshdjdf.eu-west-1.rds.amazonaws.com --port=5432 --user=my_master_user --password --dbname=postgres
    

    我们将使用PGPASSWORD=QghyumjB3ZtCQkdf替换--password标志。因此,它将是:

    PGPASSWORD=QghyumjB3ZtCQkdf psql --host=aurora-postgres.cluster-fgshdjdf.eu-west-1.rds.amazonaws.com --port=5432 --user=my_master_user --dbname=postgres
    

    这样您将不需要输入密码。


    11
    将pg_env.sh的内容添加到我的.bashrc文件中:
    cat /opt/PostgreSQL/10/pg_env.sh
    
    #!/bin/sh
    # The script sets environment variables helpful for PostgreSQL
    
    export PATH=/opt/PostgreSQL/10/bin:$PATH
    export PGDATA=/opt/PostgreSQL/10/data
    export PGDATABASE=postgres
    export PGUSER=postgres
    export PGPORT=5433
    export PGLOCALEDIR=/opt/PostgreSQL/10/share/locale
    export MANPATH=$MANPATH:/opt/PostgreSQL/10/share/man
    

    根据用户4653174的建议,增加了以下内容:

    export PGPASSWORD='password'
    

    网页内容由stack overflow 提供, 点击上面的
    可以查看英文原文,
    原文链接