Opção Bash para obter o caminho do executável resolvido?

1

O Bash é capaz de rastrear comandos de script de execução com a opção de linha de comando -x . Cada comando é então enviado para stderr , prefixado por PS4 conforme declarado na página man.

 -x      After expanding each simple command, for command,  case  command,
         select  command,  or arithmetic for command, display the expanded
         value of PS4, followed by the command and its expanded  arguments
         or associated word list.

Embora seja útil, o caminho do executável resolvido de cada comando não é fornecido. Então eu tenho que descobrir qual executável foi executado por adivinhar aliases de shell e PATH valor ao ler o rastreamento de execução.

Por exemplo, ruby tem vários candidatos de comando na minha estação de trabalho:

$ type -a ruby
ruby is /home/cbliard/.rvm/rubies/ruby-2.1.0/bin/ruby
ruby is /home/cbliard/.rvm/bin/ruby
ruby is /usr/bin/ruby
ruby is /home/cbliard/.rvm/bin/ruby

Se você executar este script com /bin/bash -x

#!/bin/bash
echo "compute"
ruby script/run_something.rb
echo "deploy"
bundle install
bundle exec cap deploy

A execução do rastreamento será

+ echo "compute"
compute
+ ruby script/run_something.rb
[output of ruby script]
+ bundle install
Using rake (10.1.0)
Using i18n (0.6.9)
[...]
Your bundle is complete!
Use 'bundle show [gemname]' to see where a bundled gem is installed.
+ bundle exec cap deploy
    triggering load callbacks
  * 2014-01-14 09:12:42 executing 'deploy'
  * 2014-01-14 09:12:42 executing 'deploy:update'
[...]
Finished: SUCCESS

Eu tive algumas esquisitices com executáveis resolvidos, principalmente devido ao uso de rvm . A saída que eu gostaria é com o caminho totalmente resolvido, assim:

+ [builtin] echo "compute"
compute
+ /home/cbliard/.rvm/rubies/ruby-1.9.3-p484/bin/ruby script/run_something.rb
[output of ruby script]
+ /home/cbliard/.rvm/gems/ruby-1.9.3-p484@global/bin/bundle install
Using rake (10.1.0)
Using i18n (0.6.9)
[...]
Your bundle is complete!
Use 'bundle show [gemname]' to see where a bundled gem is installed.
+ /home/cbliard/.rvm/gems/ruby-1.9.3-p484@global/bin/bundle exec cap deploy
    triggering load callbacks
  * 2014-01-14 09:12:42 executing 'deploy'
  * 2014-01-14 09:12:42 executing 'deploy:update'
[...]
Finished: SUCCESS

Ter o comando resolvido realmente me ajudaria a depurar problemas% rvm / bundler . A opção -x ajuda muito, mas às vezes não é suficiente. Existe algum truque que ajude a conhecer as características completas dos comandos durante a execução de um script bash ? . É melhor se o script original não precisar ser modificado.

    
por cbliard 13.01.2014 / 15:03

1 resposta

4

Como uma aproximação, você poderia fazer:

trap '{ type -p -- "${BASH_COMMAND%% *}" >&3; } 3>&2 2> /dev/null' DEBUG
set -o functrace -o xtrace

O trap DEBUG é executado antes de cada comando. Durante a execução dessa armadilha, $BASH_COMMAND é definido para o comando atual. Isso inclui chamadas de função, builtins, designações ... Chamamos type -p na primeira parte até o primeiro caractere de espaço com stdout de type retdirecionado para stderr do shell (via fd 3, de forma que o xtrace output é redirecionado para /dev/null ).

Isso é uma aproximação, pois não funcionará em casos como "cmd" foo ou $CMD foo . Como por xtrace , cuidado com os redirecionamentos do stderr.

Sem modificar o script:

BASH_ENV=<(cat <<'EOF'
  trap '{ type -p -- "${BASH_COMMAND%% *}" >&3; } 3>&2 2> /dev/null' DEBUG
EOF) bash -o functrace -x your-script

Ou para tê-lo no prompt PS4 :

BASH_ENV=<(cat <<'EOF'
  { trap '{ cmdpath=$(type -p -- "${BASH_COMMAND%% *}")
      } 2> /dev/null' DEBUG;} 2> /dev/null
EOF) PS4='+[$cmdpath] ' bash -o functrace -x your-script

ou para evitar o fork:

BASH_ENV=<(cat <<'EOF'
  { trap '{ hash -- "${BASH_COMMAND%% *}";} 2> /dev/null' DEBUG;}2>/dev/null
EOF) PS4='+[${BASH_CMDS[${BASH_COMMAND%% *}]}] ' bash -o functrace -x your-script
    
por 13.01.2014 / 15:51