É possível rastrear os comandos internos para Bash?

11

Inspirado por esta pergunta, intitulado: Quando são os comandos embutidos carregados na memória , enquanto tentava responder, tentei o seguinte comando e fiquei um pouco surpreso por não conseguir executá-lo:

$ strace cd $HOME

Existe um método que eu possa usar para executar strace para os comandos internos do Bash?

    
por slm 15.09.2013 / 04:46

3 respostas

14

Se você pensar em como strace funciona, faz todo o sentido que nenhum dos recursos internos do Bash seja rastreável. strace só pode rastrear executáveis reais, enquanto os builtins não são.

Por exemplo, meu comando cd :

$ type cd
cd is a function
cd () 
{ 
    builtin cd "$@";
    local result=$?;
    __rvm_project_rvmrc;
    __rvm_after_cd;
    return $result
}

Truque para o cd strace'ing?

Me deparei com essa técnica em que você poderia invocar strace no processo bash real e, ao fazer isso, traçar indiretamente cd dessa maneira.

Exemplo

$ stty -echo
$ cat | strace bash > /dev/null

O que resulta na capacidade de rastrear o processo bash da seguinte forma:

....
getegid()                               = 501
getuid()                                = 500
getgid()                                = 501
access("/bin/bash", X_OK)               = 0
stat("/bin/bash", {st_mode=S_IFREG|0755, st_size=940312, ...}) = 0
geteuid()                               = 500
getegid()                               = 501
getuid()                                = 500
getgid()                                = 501
access("/bin/bash", R_OK)               = 0
getpgrp()                               = 32438
rt_sigaction(SIGCHLD, {0x43e360, [], SA_RESTORER, 0x34e7233140}, {SIG_DFL, [], SA_RESTORER, 0x34e7233140}, 8) = 0
getrlimit(RLIMIT_NPROC, {rlim_cur=1024, rlim_max=62265}) = 0
rt_sigprocmask(SIG_BLOCK, NULL, [], 8)  = 0
fcntl(0, F_GETFL)                       = 0 (flags O_RDONLY)
fstat(0, {st_mode=S_IFIFO|0600, st_size=0, ...}) = 0
lseek(0, 0, SEEK_CUR)                   = -1 ESPIPE (Illegal seek)
rt_sigprocmask(SIG_BLOCK, NULL, [], 8)  = 0
read(0, 

Este é o prompt do Bash, onde ele está lá, esperando por alguma entrada. Então, vamos dar o comando cd .. :

read(0, "c", 1)                         = 1
read(0, "d", 1)                         = 1
read(0, " ", 1)                         = 1
read(0, ".", 1)                         = 1
read(0, ".", 1)                         = 1
read(0, "\n", 1)                        = 1
stat("/home", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
stat("/home/saml", {st_mode=S_IFDIR|0700, st_size=32768, ...}) = 0
stat("/home/saml/tst", {st_mode=S_IFDIR|0775, st_size=4096, ...}) = 0
stat("/home/saml/tst/90609", {st_mode=S_IFDIR|0775, st_size=4096, ...}) = 0
stat("/home/saml/tst/90609", {st_mode=S_IFDIR|0775, st_size=4096, ...}) = 0
chdir("/home/saml/tst")                 = 0
rt_sigprocmask(SIG_BLOCK, NULL, [], 8)  = 0
read(0, 

Da saída acima, você pode ver onde digitei o comando cd .. e tecle enter, ( \n ). De lá você pode ver que a função stat() foi chamada, e que depois Bash está sentado em outro prompt read(0.. , esperando por outro comando.

    
por 15.09.2013 / 04:57
7

Para strace do shell fazendo cd /some/dir :

{ strace -p "$$" & sleep 1; cd /some/dir; kill "$!"; }
    
por 15.09.2013 / 20:46
1

Você pode tentar o seguinte:

strace bash -c <command/builtin>

Por exemplo:

strace bash -c 'cd /path/to/destination/'
    
por 20.09.2018 / 17:22