七的博客

一次Linux切换用户命令引发的思考

Linux

一次Linux切换用户命令引发的思考

最近在测试环境一台 Linux 服务器中重启 PostgreSQL 数据库,碰到个很奇怪的问题,一直提示命令未找到,随即开始了一顿排查。

1. 问题复现

先看下现象,首先从 root 用户切换到 postgres 用户:

[root@localhost pgdata]# su postgres

然后查看 PostgreSQL 的状态一直提示找不到:

bash-4.4$ pg_ctl status  // 
bash: pg_ctl: command not found

查看 pg_ctl 程序的位置是空白的:

bash-4.4$ whereis pg_ctl
pg_ctl:

到 PostgreSQL 的安装目录去看看情况:

bash-4.4$ cd /usr/pgsql-11/

bash-4.4$ ls  // 查看当前目录下的文件列表
clusterdb   dropdb    oid2name		 pgbench	 pg_ctl(程序就在这里目录下)      pg_isready      pg_resetwal  pg_standby	  pg_upgrade	       postgres			   postmaster  vacuumdb
createdb    dropuser  pg_archivecleanup  pg_config	 pg_dump     pg_receivewal   pg_restore   pg_test_fsync   pg_verify_checksums  postgresql-11-check-db-dir  psql        vacuumlo
createuser  initdb    pg_basebackup	 pg_controldata  pg_dumpall  pg_recvlogical  pg_rewind	  pg_test_timing  pg_waldump	       postgresql-11-setup	   reindexdb

在当前目录下试试:

bash-4.4$ ./pg_ctl status

pg_ctl: no database directory specified and environment variable PGDATA unset
Try "pg_ctl --help" for more information.

看到上面的这个提示大概就猜到了,应该是跟环境变量有关系。那就直接设置一波环境变量:

bash-4.4$ export PGDATA=/home/postgres/pgdata

bash-4.4$ pg_ctl status
pg_ctl: server is running (PID: 1473116)
/usr/pgsql-11/bin/postgres

配置好环境变量后直接执行命令是可以的,说明问题是出现在环境变量上的。 这时候发现命令行里的前缀 bash-4.4$ 不太正常,居然没有显示出用户名来。 猜想应该是我切换用户的指令写的不对,重新检查一遍。

2. 问题解决

刚才的写法是:

[root@localhost pgdata]# su postgres

问题就出现在这里,少了一个 - , 然后修改一下命令:

[root@localhost pgdata]# su -  postgres 

直接执行 pg_ctl 查看下数据库服务在不在运行:

[postgres@localhost ~]$ pg_ctl status

pg_ctl: server is running (PID: 1473116)
/usr/pgsql-11/bin/postgres

查看 pg_ctl 程序位置:

[postgres@localhost ~]$ whereis pg_ctl
pg_ctl: /usr/pgsql-11/bin/pg_ctl

重启数据库:

[postgres@localhost ~]$ pg_ctl restart
waiting for server to shut down...... done
server stopped
waiting for server to start....
LOG:  listening on IPv4 address "0.0.0.0", port 5432

3. 为什么会出现这个问题

首先查看下 su 命令的帮助文档:


bash-4.4$ su --hlep
su: unrecognized option '--hlep'
Try 'su --help' for more information.
bash-4.4$ su --help

Usage:
 su [options] [-] [<user> [<argument>...]]

Change the effective user ID and group ID to that of <user>.
A mere - implies -l.  If <user> is not given, root is assumed.

Options:
 -m, -p, --preserve-environment  do not reset environment variables
 -g, --group <group>             specify the primary group
 -G, --supp-group <group>        specify a supplemental group

 -, -l, --login                  make the shell a login shell     // 注意这里,加上这个命令后会启动一个登录 shell,加载该用户的环境变量
 -c, --command <command>         pass a single command to the shell with -c
 --session-command <command>     pass a single command to the shell with -c
                                   and do not create a new session
 -f, --fast                      pass -f to the shell (for csh or tcsh)
 -s, --shell <shell>             run <shell> if /etc/shells allows it
 -P, --pty                       create a new pseudo-terminal

 -h, --help                      display this help
 -V, --version                   display version

For more details see su(1).

再用 man 详细看看命令的文档:

bash-4.4$ man su

SYNOPSIS
       su [options] [-] [user [argument...]]

DESCRIPTION
       su allows to run commands with a substitute user and group ID.

       When called without arguments, su defaults to running an interactive shell as root.

       For  backward compatibility, su defaults to not change the current directory and to only set the environment variables HOME and SHELL (plus USER and LOGNAME if the target user is not root).  It is rec‐
       ommended to always use the --login option (instead of its shortcut -) to avoid side effects caused by mixing environments.

       This version of su uses PAM for authentication, account and session management.  Some configuration options found in other su implementations, such as support for a wheel group, have to  be  configured
       via PAM.

       su  is mostly designed for unprivileged users, the recommended solution for privileged users (e.g. scripts executed by root) is to use non-set-user-ID command runuser(1) that does not require authenti‐
       cation and provide separate PAM configuration. If the PAM session is not required at all then the recommend solution is to use command setpriv(1).

OPTIONS
       -c, --command=command
              Pass command to the shell with the -c option.

       -f, --fast
              Pass -f to the shell, which may or may not be useful, depending on the shell.

       -g, --group=group
              Specify the primary group.  This option is available to the root user only.

       -G, --supp-group=group
              Specify a supplemental group.  This option is available to the root user only.  The first specified supplementary group is also used as a primary group if the option --group is unspecified.

       -, -l, --login    // 注意这个
      
              Start the shell as a login shell with an environment similar to a real login:  

                 o      clears all the environment variables except TERM

                 o      initializes the environment variables HOME, SHELL, USER, LOGNAME, and PATH

                 o      changes to the target user's home directory

                 o      sets argv[0] of the shell to '-' in order to make the shell a login shell

       -m, -p, --preserve-environment
              Preserve the entire environment, i.e. it does not set HOME, SHELL, USER nor LOGNAME.  This option is ignored if the option --login is specified.

- 就是 -l--login 的别名, 作用是:

  • 用这个命令可以像重新登录一样重新启动命令行界面。

  • 除了 TERM 以外,其他的环境变量都会被清空。

  • 重新设置环境变量,包括 HOME(家目录),SHELL(使用的 shell 类型),USER(用户名),LOGNAME(登录名),和 PATH(可执行文件搜索路径)。

  • 自动切换到要切换的用户的家目录。。

  • 把命令行的名字设置为 ‘-‘,这样就能让它作为登录后的命令行来运行。

4. 总结下两种切换用户命令区别

4.1 su - postgres (带 - 字符):

  • 使用 su -su -l 时,会启动一个登录 shell。
  • 完全模拟 postgres 用户的登录环境 , 类似于该用户直接登录系统一样。
  • 切换用户后 , 当前工作目录将更改为 postgres 用户的主目录。
  • 加载 postgres 用户的个人配置文件 , 如 .profile.bash_profile 等。
  • 环境变量将被重置为 postgres 用户的默认值。

4.2 su postgres (不带 - 字符):

  • 使用 su 时,会启动一个普通的 shell , 而不是登录 shell。
  • 只切换到 postgres 用户 , 不会完全模拟登录环境。
  • 切换用户后 , 当前工作目录保持不变。
  • 不会加载 postgres 用户的个人配置文件。
  • 环境变量保持不变 , 继承自之前的用户环境。

通常还是使用 su - postgres 来切换用户比较实用 , 这种方式提供了一个干净独立的 postgres 用户环境。这对于运行需要特定环境设置的 PostgreSQL 命令和工具非常有用。