如何“散列-r”并刷新所有 shell?

如何“散列-r”并刷新所有 shell?

这与hash命令的目的是什么?安装程序后,我正在寻找一种方法来告诉所有打开的 shell 更新其缓存。我经常打开 6 到 8 个,但我不想运行hash -r8 或 10 次。任何事情超过一次都是浪费时间和精力。

在一个 shell 中安装程序后,是否可以 (1) 让所有 shell 重建其缓存程序的视图;或者 (2) 重建表并将该表用于所有其他 shell?如果可以的话,我们该怎么做呢?


这是 的相关部分man 1 hash,但没有讨论如何在全球范围内取得成果。

   hash [-lr] [-p filename] [-dt] [name]
          Each time hash is invoked, the full pathname of the command name
          is  determined  by searching the directories in $PATH and remem‐
          bered.  Any previously-remembered pathname is discarded.  If the
          -p option is supplied, no path search is performed, and filename
          is used as the full filename of  the  command.   The  -r  option
          causes  the  shell  to  forget all remembered locations.  The -d
          option causes the shell to forget  the  remembered  location  of
          each  name.   If the -t option is supplied, the full pathname to
          which each name corresponds is printed.  If multiple name  argu‐
          ments  are  supplied  with  -t,  the  name is printed before the
          hashed full pathname.  The -l option causes output  to  be  dis‐
          played in a format that may be reused as input.  If no arguments
          are given, or if only -l is supplied, information  about  remem‐
          bered  commands  is printed.  The return status is true unless a
          name is not found or an invalid option is supplied.

答案1

这是 TLDR 解决方案:如果您想以编程方式在预先存在的 shell 会话中执行命令,那么您可以使用该ttyecho程序。

警告: 请注意,这通常不是一个安全的操作,并且对每个会话的状态很敏感。正如用户 StephenKitt 指出的那样,这种方法要求每个终端会话都有一个等待接收输入的提示。

PROMPT_COMMAND='hash -r'另一种解决方案是通过将语句添加到文件中来有效禁用路径散列~/.bashrc。这不会影响当前正在运行的会话,但会防止将来出现此问题。

最后,您可以考虑使用终端多路复用器,例如多路复用器,支持在多个终端同时执行命令。

以下是更详细的回应。


在我看来,您正在寻找的基本功能是能够在其他活动 shell 会话中以编程方式执行命令。我发现这个问题(如何在其他 shell 会话中执行命令)已在本网站的其他地方得到解决,例如:

在其他活动 shell 会话中执行命令的最简单方法似乎是使用该ttyecho实用程序。该ttyecho程序是一个小型、独立的单文件 C 程序。以下是ttyecho源代码和文档的一些参考:

为了完整起见,这里是源代码:

// ttyecho.c
// Original author: Pratik Sinha
// http://www.humbug.in/2010/utility-to-send-commands-or-data-to-other-terminals-ttypts/

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <string.h>
#include <unistd.h>

void print_help(char *prog_name) {
    printf("Usage: %s [-n] DEVNAME COMMAND\n", prog_name);
    printf("Usage: '-n' is an optional argument if you want to push a new line at the end of the text\n");
    printf("Usage: Will require 'sudo' to run if the executable is not setuid root\n");
    exit(1);
}

int main (int argc, char *argv[]) {
    char *cmd, *nl = "\n";
    int i, fd;
    int devno, commandno, newline;
    int mem_len;
    devno = 1; commandno = 2; newline = 0;
    if (argc < 3) {
        print_help(argv[0]);
    }
    if (argc > 3 && argv[1][0] == '-' && argv[1][1] == 'n') {
        devno = 2; commandno = 3; newline=1;
    } else if (argc > 3 && argv[1][0] == '-' && argv[1][1] != 'n') {
        printf("Invalid Option\n");
        print_help(argv[0]);
    }
    fd = open(argv[devno],O_RDWR);
    if(fd == -1) {
        perror("open DEVICE");
        exit(1);
    }
    mem_len = 0;
    for ( i = commandno; i < argc; i++ ) {
        mem_len += strlen(argv[i]) + 2;
        if ( i > commandno ) {
            cmd = (char *)realloc((void *)cmd, mem_len);
        } else { //i == commandno
            cmd = (char *)malloc(mem_len);
        }

        strcat(cmd, argv[i]);
        // strcat(cmd, " ");
    }
  if (newline == 0)
        usleep(225000);
    for (i = 0; cmd[i]; i++)
        ioctl (fd, TIOCSTI, cmd+i);
    if (newline == 1)
        ioctl (fd, TIOCSTI, nl);
    close(fd);
    free((void *)cmd);
    exit (0);
}

如果您下载源代码或将其复制粘贴到名为 的文件中ttyecho.c,那么您应该能够像这样编译程序:

gcc ttyecho.c -o ttyecho

程序编译完成后,您应该能够使用它在另一个 shell 会话中运行您想要的任何命令。这包括能够hash -r在每个活动 shell 会话中以编程方式运行命令。以下是清除 Mac OS X 上所有 shell 会话上的散列命令的一种方法:

for _tty in /dev/ttys*; do ./ttyecho -n 'hash -r' ${_tty}; done

在 Linux 机器上,你可以这样做:

for _tty in /dev/pts/*; do ./ttyecho -n 'hash -r' ${_tty}; done

由于一些评论要求找到一种重现该问题的方法,因此我添加了以下脚本来说明哈希如何影响执行的程序。

# Create two bin directories
mkdir -p ~/local/bin1
mkdir -p ~/local/bin2

# Add the directories to the PATH, with bin2 preceding bin1
export PATH="${HOME}/local/bin2:${HOME}/local/bin1:${PATH}"

# Create a test script and put it in the bin1 directory
cat <<HEREDOC > ~/local/bin1/test.sh
#!/bin/bash
# test.sh

echo "This is test #1, it's in ~/local/bin1"
HEREDOC

# Make the script executable
chmod +x ~/local/bin1/test.sh

# Verify that the script is found by using the "which" command
which test.sh

# Output:
#
#   /home/username/local/bin1/test.sh

# Verify that the script is found by using the "type" command
type test.sh

# Output:
#
#   test.sh is /home/username/local/bin1/test.sh

# Test the script
test.sh

# Output:
#
#   This is test #1, it's in ~/local/bin1

# Now hash the test script
hash test.sh

# Verify that the script has been hashed by using the "type" command
type test.sh

# Output:
#
#   test.sh is hashed (/home/username/local/bin1/test.sh)

# Now create a second test script and put it in bin2 to shadow the first
cat <<HEREDOC > ~/local/bin2/test.sh
#!/bin/bash
# test.sh

echo "This is test #2, it's in ~/local/bin2"
HEREDOC

# Make the second test script executable
chmod +x ~/local/bin2/test.sh

# Verify that the bin2 test script take priority over the bin1 test script
which -a test.sh

# Output:
#
#   /home/username/local/bin2/test.sh
#   /home/username/local/bin1/test.sh

which test.sh

# Output:
#
#   /home/username/local/bin2/test.sh

# Try to run the test script
test.sh

# Ouput:
#
#   This is test #1, it's in ~/local/bin1

# NOTE: Even though bin2/test.sh comes before bin1/test.sh in the PATH,
#       it's bin1/test.sh that is executed. What's going on?

# Use the "type" command to see which script is being executed
type test.sh

# Output
#
#   test.sh is hashed (/home/username/local/bin1/test.sh)

# NOTE: That explains the seeming contradiction.

# Clear the hashed command
hash -d test.sh

# Check that the hashed command has been cleared
type test.sh

# Output:
#
#   test.sh is /home/username/local/bin2/test.sh

# Run the test.sh command
test.sh

# Output:
#
#   This is test #2, it's in ~/local/bin2

我还发现了本网站其他地方描述的替代方法:

解决方案是使用PROMPT_COMMAND变量不断清除路径缓存,例如通过将以下行添加到您的~/.bashrc

PROMPT_COMMAND='hash -r'

请注意,这只会影响新会话,而不会影响您预先存在的会话,除非您也在这些会话中执行该命令。

最后,您可能需要考虑使用终端多路复用器,例如多路复用器。这是该网站的相关帖子:

相关内容