bash 提示转义序列 \h 从哪里获取主机名?

Where does bash prompt escape sequence \h get the hostname from?

\h 是扩展到主机名的 bash 提示符转义序列。它从哪里获得主机名?在我的系统上,它显示了一个我在任何地方都找不到的值,不在 hostname -f/etc/hosts/etc/hostname/etc/sysconfig/network$HOSTNAME 中。所以我想知道它是从哪里得到的。我的系统是 Centos 7.4。我知道有一些隐藏的地方存储了诸如 UUID 之类的东西,我似乎记得我以前遇到过类似的隐藏主机名类型的问题,但我记不起细节了。

它可能(只是一个猜测)使用 gethostname(2) system call (which is handled by the kernel, as all syscalls(2) 是...)

顺便说一句,GNU bash is (as most packages of your Linux distributions are) free software; so please download its source code and study it; use the source, Luke! and open the source more,请。

一个更有趣的问题是 bash 如何缓存该信息。它会在每个命令中调用 gethostname 吗?您也可以使用 strace(1) 来找出答案。


当然,每次好奇的时候,养成研究免费软件源代码的习惯。并使用 strace - 和 gdb 调试器 - 了解它们的动态行为。

一位法国歌手,G.Bedos,告诉我们"La liberté ne s'use que si on ne s'en sert pas",那就是

Freedom wears out if you don't use it.

(翻译是我的,我是法语但母语不是英语)


所以下次,请深入研究免费软件的源代码行使你的自由很重要,这就是free software is about

如果您查看 bash source code you'll see in shell.c that it calls gethostname(2),一个从内核检索主机名的 POSIX 系统调用。

/* It's highly unlikely that this will change. */
if (current_host_name == 0)
  {
    /* Initialize current_host_name. */
    if (gethostname (hostname, 255) < 0)
      current_host_name = "??host??";
    else
      current_host_name = savestring (hostname);
  }

这不一定是规范字符串。内核实际上并不知道机器的网络主机名。它只是报告传递给 sethostname(2). To quote from the uname(2) man page:

的任何内容

On the other hand, the [hostname] is meaningless: it gives the name of the present machine in some undefined network, but typically machines are in more than one network and have several names. Moreover, the kernel has no way of knowing about such things, so it has to be told what to answer here.

在没有 gethostname(2) 的非 Linux 系统上,bash 退回到 uname(2)。如果 uname(2) 甚至不可用,那么它只会显示 "unknown"。您可以在 lib/sh/oslib.c:

中看到该逻辑
#if !defined (HAVE_GETHOSTNAME)
#  if defined (HAVE_UNAME)
#    include <sys/utsname.h>
int
gethostname (name, namelen)
     char *name;
     int namelen;
{
  int i;
  struct utsname ut;

  --namelen;

  uname (&ut);
  i = strlen (ut.nodename) + 1;
  strncpy (name, ut.nodename, i < namelen ? i : namelen);
  name[namelen] = '[=11=]';
  return (0);
}
#  else /* !HAVE_UNAME */
int
gethostname (name, namelen)
     char *name;
     int namelen;
{
  strncpy (name, "unknown", namelen);
  name[namelen] = '[=11=]';
  return 0;
}
#  endif /* !HAVE_UNAME */
#endif /* !HAVE_GETHOSTNAME */
如果主机名更改,

\h 不会更新。当 shell 初始化时,该值在启动时被缓存。

[jkugelman@malkovich]$ hostname
malkovich
[jkugelman@malkovich]$ sudo hostname kaufman
[jkugelman@malkovich]$ hostname
kaufman
[jkugelman@malkovich]$ bash
[jkugelman@kaufman]