Inspired by this question, titled: When are the built-in commands loaded to memory, while attempting to answer this I tried the following command and was a bit surprised that I couldn’t run it:
$ strace cd $HOME
Is there a method I can make use of to run strace for the builtin commands to Bash?
Answers:
Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.
Method 1
If you think about how strace
works then it makes total sense that none of the builtins to Bash would be traceable. strace
can only trace actual executables, whereas the builtins are not.
For example, my cd
command:
$ type cd cd is a function cd () { builtin cd "<a href="https://getridbug.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="cde98d">[email protected]</a>"; local result=$?; __rvm_project_rvmrc; __rvm_after_cd; return $result }
Trick for strace’ing cd?
I came across this technique where you could invoke strace
on the actual bash
process and in so doing, indirectly trace cd
that way.
Example
$ stty -echo $ cat | strace bash > /dev/null
Which results in me being able to strace the
bash
process as follows:.... 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,
This is the Bash prompt, where it’s sitting there, waiting for some input. So let’s give it the command
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,
From the above output, you can see where I typed the command,
cd ..
and hit enter, (n
). From there you can see that the stat()
function was called, and that afterwards Bash is sitting at another read(0..
prompt, waiting for another command.
Method 2
To strace
the shell doing cd /some/dir
:
{ strace -p "$$" & sleep 1; cd /some/dir; kill "$!"; }
Method 3
You can try the following:
strace bash -c <command/builtin>
For example:
strace bash -c 'cd /path/to/destination/'
All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0