"hash -r"を使ってすべてのシェルを更新するには?

"hash -r"を使ってすべてのシェルを更新するには?

これは以下に関連しています。ハッシュコマンドの目的は何ですか?プログラムをインストールした後、開いているすべてのシェルにキャッシュを更新するように指示する方法を探しています。普通6~8個浮かぶのにhash -r8~10個は走りたくないんですよ。何かを複数回するのは時間とエネルギーの無駄です。

1つのシェルにプログラムをインストールした後(1)すべてのシェルにキャッシュされたプログラムのビューを再作成するか(2)テーブルを再作成し、他のすべてのシェルにそのテーブルを使用できますか?それではどうすればいいですか?


関連部分なのに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ソリューションは次のとおりです。既存のシェルセッションでプログラムでコマンドを実行したい場合は、このttyechoプログラムを使用できます。

警告する: これは通常安全な作業ではなく、各セッションの状態に敏感です。 StephenKittユーザーが指摘したように、このアプローチでは各ターミナルセッションで入力を受信するのを待つプロンプトが必要です。

PROMPT_COMMAND='hash -r'別の解決策は、ファイルにステートメントを追加してパスハッシュを効果的に無効にすることです~/.bashrc。これは現在実行中のセッションには影響しませんが、将来この問題が発生するのを防ぎます。

最後に、端末マルチプレクサの使用を検討することができます。マルチプレクサ、同時に複数の端末でコマンド実行をサポートします。

詳細な答えは次のとおりです。


あなたが探している基本機能は、他のアクティブシェルセッション内でプログラムでコマンドを実行する機能のようです。この質問(他のシェルセッションでコマンドを実行する方法)は、このサイトの他の場所で解決されました。たとえば、次のようになります。

他のアクティブシェルセッションでコマンドを実行する最も簡単な方法は、このユーティリティを使用するようです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

プログラムがコンパイルされたら、それを使用して他のシェルセッションで目的のコマンドを実行できます。これには、hash -r各アクティブシェルセッション内でプログラム的にコマンドを実行する機能が含まれます。 Mac OS Xのすべてのシェルセッションでハッシュされたコマンドを消去する1つの方法は次のとおりです。

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'

そのセッションでもコマンドを実行しない限り、これは既存のセッションではなく新しいセッションにのみ影響します。

最後に、端末マルチプレクサの使用を検討することもできます。マルチプレクサ。サイトの関連投稿は次のとおりです。

関連情報