Como 'hash -r' e atualizar todos os shells?

3

Isso está relacionado a Qual é o objetivo do comando hash? Depois de instalar um programa, estou procurando uma maneira de dizer a todos os shells abertos para atualizar seu cache. Muitas vezes tenho 6 a 8 deles abertos e não quero ter que executar hash -r 8 ou 10 vezes. Qualquer coisa mais que uma vez é perda de tempo e esforço.

Depois de instalar um programa em um shell, é possível (1) fazer com que todos os shells reconstruam sua visão dos programas armazenados em cache; ou (2) reconstruir a tabela e usar essa tabela para todos os outros shells? Se é possível, então como fazemos isso?

Aqui está a seção relevante de man 1 hash , mas não discute como alcançar resultados globalmente.

   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.
    
por jww 13.10.2017 / 23:55

1 resposta

0

Aqui está a solução TLDR: se você quer executar comandos programaticamente em sessões shell pré-existentes, então você pode usar o programa ttyecho .

AVISO: Observe que esta não é, em geral, uma operação segura e é sensível ao estado de cada sessão. Como o usuário StephenKitt aponta, essa abordagem requer que cada sessão de terminal tenha um prompt que esteja esperando para receber informações.

Uma solução alternativa seria desativar efetivamente o hash de caminho adicionando a instrução PROMPT_COMMAND='hash -r' ao seu arquivo ~/.bashrc . Isso não afetará as sessões em execução no momento, mas evitará que esse problema apareça no futuro.

Finalmente, você pode considerar o uso de um multiplexador de terminal, como tmux , que suporta a execução de comandos em vários terminais simultaneamente.

Segue-se uma resposta mais detalhada.

Parece-me que a funcionalidade básica que você está procurando é a capacidade de executar comandos por meio de programação em outras sessões de shell ativas. Descobri que essa questão (de como executar comandos em outras sessões do shell) foi abordada em outro lugar neste site, por exemplo:

Parece que a maneira mais fácil de executar comandos em outras sessões de shell ativas é usar o utilitário ttyecho . O programa ttyecho é um programa C pequeno, autônomo e de arquivo único. Aqui estão algumas referências ao código-fonte e à documentação do ttyecho :

Para completar, aqui está o código fonte:

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

Se você baixar o código-fonte ou copiá-lo e colá-lo em um arquivo chamado ttyecho.c , então você deve ser capaz de compilar o programa da seguinte forma:

gcc ttyecho.c -o ttyecho

Uma vez que o programa é compilado, você deve ser capaz de usá-lo para executar qualquer comando que desejar na sessão de shell. Isso inclui a capacidade de executar programaticamente o comando hash -r em todas as sessões ativas do shell. Aqui está uma maneira de limpar os comandos com hash em todas as sessões de shell no Mac OS X:

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

Em uma máquina Linux, você faria algo assim:

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

Como alguns comentários pediram uma maneira de reproduzir o problema, incluí o seguinte script para ilustrar como o hashing pode afetar o programa que é executado.

# 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

Também encontrei uma abordagem alternativa descrita em outro lugar neste site:

A solução foi usar a variável PROMPT_COMMAND para limpar continuamente o cache do caminho, por exemplo, adicionando a seguinte linha ao seu ~/.bashrc :

PROMPT_COMMAND='hash -r'

Observe que isso afetará apenas as novas sessões e não as sessões pré-existentes, a menos que você também execute esse comando nessas sessões.

Finalmente, você pode querer considerar o uso de um multiplexador de terminal, como tmux . Aqui está um post relevante deste site:

por 16.10.2017 / 06:27