Modifique todos os comandos bash através de um programa antes de executá-los

2

Estou tentando criar um programa que exija esse recurso. O fluxo será como:

  • Usuário insira um comando bash
  • O usuário pressionou a entrada
  • Meu script receberá o comando, o diretório atual, .. como variáveis. O programa pode opcionalmente modificar o comando.
  • O comando modificado será executado normalmente.

Existe alguma maneira de fazer isso?

Nota: eu preciso disso para meu uso pessoal, não vou distribuir este programa.

    
por VarunAgw 21.12.2015 / 15:04

4 respostas

7

Eu fiz algumas pesquisas sobre isso. Podemos usar a opção bash TRAP e shopt para conseguir isso.

Adicione isto ao .bash_profile

shopt -s extdebug

preexec_invoke_exec () {
    [ -n "$COMP_LINE" ] && return  # do nothing if completing
    [ "$BASH_COMMAND" = "$PROMPT_COMMAND" ] && return # don't cause a preexec for $PROMPT_COMMAND
    local this_command='HISTTIMEFORMAT= history 1 | sed -e "s/^[ ]*[0-9]*[ ]*//"';

    # So that you don't get locked accidentally
    if [ "shopt -u extdebug" == "$this_command" ]; then
        return 0
    fi

    # Modify $this_command and then execute it
    return 1 # This prevent executing of original command
}
trap 'preexec_invoke_exec' DEBUG

Funciona assim:

trap 'function_name' DEBUG faz com que function_name seja executado antes de executar comandos bash. Mas, por padrão, return value não tem efeito sobre o comando original.

shopt -s extdebug habilita alguns recursos de depuração com um deles verifica o valor de retorno antes de executar o comando original.

Nota: shopt -u extdebug desabilita esse recurso para que o comando original sempre seja executado.

Documentação de extdebug (Veja o segundo recurso):

If set, behavior intended for use by debuggers is enabled:

The -F option to the declare builtin (see Bash Builtins) displays the source file name and line number corresponding to each function name supplied as an argument.
If the command run by the DEBUG trap returns a non-zero value, the next command is skipped and not executed.
If the command run by the DEBUG trap returns a value of 2, and the shell is executing in a subroutine (a shell function or a shell script executed by the . or source builtins), a call to return is simulated.
BASH_ARGC and BASH_ARGV are updated as described in their descriptions (see Bash Variables).
Function tracing is enabled: command substitution, shell functions, and subshells invoked with ( command ) inherit the DEBUG and RETURN traps.
Error tracing is enabled: command substitution, shell functions, and subshells invoked with ( command ) inherit the ERR trap.
    
por 21.12.2015 / 22:29
1

Você pode chegar ao seu objetivo com um script bash simples que usa o sistema readline integrado para obter uma linha. Por exemplo:

#!/bin/bash -i
while read -e -p '$ ' line
do    echo "your cmd: $line"
      eval "$line"
done

O script lê uma linha de entrada (a menos que o fim do arquivo) usando edição de linha de leitura (-e) e, em seguida, ecoa e executa. Observe o -i no #! para garantir que o script seja interativo. Você pode construir seu código para manipular o comando de entrada com base nisso. Por exemplo,

#!/bin/bash -i

myfn(){
  echo "in dir $1. doing: $2" >&2
  echo "$2" # manipulate command here and echo the result
}

while read -e -p "$PS1" line
do    newcmd=$(myfn "$PWD" "$line")
      eval "$newcmd"
done
    
por 21.12.2015 / 17:11
0

Instale as funções bash-preexec - preexec e precmd para o Bash como Zsh

Two functions preexec and precmd can now be defined and they'll be automatically invoked by bash-preexec if they exist.

  • preexec Executed just after a command has been read and is about to be executed. The string that the user typed is passed as the first argument.
  • precmd Executed just before each prompt. Equivalent to PROMPT_COMMAND, but more flexible and resilient.

.

source ~/.bash-preexec.sh
preexec() { echo "just typed $1"; }
precmd() { echo "printing the prompt"; }

Should output something like:

elementz@Kashmir:~/git/bash-preexec (master)$ ls
just typed ls
bash-preexec.sh  README.md  test
printing the prompt

You can also define functions to be invoked by appending them to two different arrays. This is great if you want to have many functions invoked for either hook.

    
por 05.09.2016 / 04:19
-1

Em qualquer script de shell, o comando atualmente em execução está disponível como $0 , e o diretório atual pode ser facilmente recuperado com uma chamada para pwd . Para fazer o que você quer, você terá que escrever um programa que possa ser usado como shell, e então definir o valor do shell do seu usuário para aquele programa.

    
por 21.12.2015 / 15:09