You can't strace internal commands directly because strace works by taking the name of a program and some arguments to it, and executes that program (creating a new process for it). A shell-internal is by definition not a program for which a new process is created - it is just a routine which runs in the existing shell process.
Here's one way to do it indirectly, by using strace on the bash process itself. I used
cat instead of letting the shell read directly from the terminal, since a non-interactive shell will be created, and that doesn't produce a huge number of signal handling calls between commands. I also turn off echo to prevent the typed input and the strace output getting mixed up:
Code:
stty -echo
cat | strace bash > /dev/null
After the initial strace output from all the system calls used to create and initialise the new process, you can type in commands and see the system calls generated. For example, the command "echo hello world" produces this output:
Code:
read(0, "e", 1) = 1
read(0, "c", 1) = 1
read(0, "h", 1) = 1
read(0, "o", 1) = 1
read(0, " ", 1) = 1
read(0, "h", 1) = 1
read(0, "e", 1) = 1
read(0, "l", 1) = 1
read(0, "l", 1) = 1
read(0, "o", 1) = 1
read(0, " ", 1) = 1
read(0, "w", 1) = 1
read(0, "o", 1) = 1
read(0, "r", 1) = 1
read(0, "l", 1) = 1
read(0, "d", 1) = 1
read(0, "\n", 1) = 1
write(1, "hello world\n", 12) = 12
rt_sigprocmask(SIG_BLOCK, NULL, [], 8) = 0
As I said before, you will get
read calls. This will always be the case, for any command, so strictly speaking the answer to the question is that all commands produce system calls. There are no exceptions. However, I expect the questioner didn't mean it quite like that.
In the case of echo, you get a
write system call, and this will be the case with any builtin command which produces any output.
Commands which only change the internal state of the shell like
alias or setting a variable will not do this, so that might be the answer which the questioner is looking for. However, even for these commands the shell always calls rt_sigprocmask. It's arguable if this is done as part of the command, or in a wrapper around the command.
In my opinion, the question is too vague to give a precise answer to it, but with th caveats I have mentioned here, I think you can cover all your bases.