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

孤街醉人 提交于 2019-12-24 02:13:17

问题


\h is a bash prompt escape sequence that expands to the hostname. Where does it get the hostname from? On my system it shows a value that I cannot find anywhere, not in hostname -f or /etc/hosts or /etc/hostname or /etc/sysconfig/network or $HOSTNAME. So I'm wondering where it's getting it from. My system is Centos 7.4. I know there are hidden places where things such as UUIDs are stored, and I seem to recall that I've come across a similar hidden hostname type of issue in the past, but I can't remember the details.


回答1:


If you look at the bash source code you'll see in shell.c that it calls gethostname(2), a POSIX system call that retrieves the hostname from the kernel.

/* 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);
  }

This is not necessarily a canonical string. The kernel doesn't actually know the machine's network hostname. It just reports back whatever was passed to 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.

On non-Linux systems without gethostname(2), bash falls back to uname(2). If uname(2) isn't even available then it simply displays "unknown". You can see that logic in 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] = '\0';
  return (0);
}
#  else /* !HAVE_UNAME */
int
gethostname (name, namelen)
     char *name;
     int namelen;
{
  strncpy (name, "unknown", namelen);
  name[namelen] = '\0';
  return 0;
}
#  endif /* !HAVE_UNAME */
#endif /* !HAVE_GETHOSTNAME */

\h isn't updated if the hostname changes. The value is cached at startup when the shell is initialized.

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



回答2:


It probably (just a guess) uses the gethostname(2) system call (which is handled by the kernel, as all syscalls(2) are...)

BTW, 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, please.

A more interesting question is how that information is cached by bash. Does it call gethostname at every command? You might also use strace(1) to find out.


Of course, take the habit of studying the source code of free software every time you are curious. And use strace -and the gdb debugger- to understand their dynamic behavior.

A French singer, G.Bedos, told us "La liberté ne s'use que si on ne s'en sert pas", that is

Freedom wears out if you don't use it.

(translation is mine, I am French but not a native English speaker)


So next time, please dive into the source code of free software. It is important to exercise your freedom, and that is what free software is about.



来源:https://stackoverflow.com/questions/47061689/where-does-bash-prompt-escape-sequence-h-get-the-hostname-from

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!