1

I'm writing a bash script named test.sh as below on my Ubuntu:

#!/bin/bash

while true; do
    echo 'abc'   # pwd, df...
    sleep 1
done

When I execute ./test.sh at one terminal, I open another terminal to execute the commands below:

$ pgrep test
31110
$ ps -ef | grep sleep
me       31140  31110  0 20:58 pts/1    00:00:00 sleep 1
me       31142  16389  0 20:58 pts/0    00:00:00 grep --color=auto sleep
$ ps -ef | grep sleep
me       31146  31110  0 20:58 pts/1    00:00:00 sleep 1
me       31148  16389  0 20:58 pts/0    00:00:00 grep --color=auto sleep
$ ps -ef | grep sleep
me       31150  31110  0 20:58 pts/1    00:00:00 sleep 1
me       31152  16389  0 20:58 pts/0    00:00:00 grep --color=auto sleep

So, the PID of the process ./test.sh is 31110, and when I execute the command ps -ef | grep sleep, I get many processes of sleep 1 (PIDs are 31140, 31146, 31150...), which are all the child-processes of the process ./test.sh.

Well, for now it seems that I can understand everything, the child-processes of sleep 1 come from that loop of while true.

However, when I try to ps -ef | grep echo, I get nothing. I've also tried to execute other commands, such as pwd, df, but they can't be greped either.

So my question is why the command sleep is an independent process whereas other commands aren't.

4
  • 3
    The other commands are either built into the shell (pwd, echo), or runs too quickly for you to spot them (df).
    – Kusalananda
    Jan 14, 2021 at 13:13
  • @Kusalananda They run so quickly that I can't grep them with another infinite loop ps aux | grep CMD... Ok, I can live with that.
    – Yves
    Jan 14, 2021 at 13:24
  • 1
    Try with another command that takes a bit longer to run, such as du. Maybe du /?
    – Kusalananda
    Jan 14, 2021 at 14:00
  • You can also direct the output of df to a pipe with no reader to halt it: mkfifo /tmp/f; df > /tmp/f; rm /tmp/f. You'll need to kill it with e.g. ^C or cat /tmp/f to release the block on the pipe.
    – ilkkachu
    Jan 14, 2021 at 14:09

3 Answers 3

5

There are two aspects to consider here:

  1. echo and pwd can indeed not appear as independent processes because they are builtin commands of the bash shell (see the output of type echo e.g. - but note that they could very well be implemented as external executable, and what is or is not implemented as builtin or external program does vary from shell to shell).
  2. Commands launched by the shell that call an external executable (e.g. df) on the other hand are independent processes, but they often complete so quickly that you will have a hard time "catching" them with ps, (i.e. they are alredy finished when ps starts and for that reason won't show up in the output).
1
  • 1
    I tried with the command df, which is not builtin command, and I wrote another bash script to do an infinite loop to do ps aux | grep df, but I still can't grep the command df. Well, so we have say that the commands like df is really quick...
    – Yves
    Jan 14, 2021 at 13:23
3

sleep is an external process because Bash doesn't provide a builtin version of it by default. It wouldn't be hard to do, since the program pretty much only runs a single system call, but there are differences between implementations, some are not restricted to integer values, some take specifiers like m for minutes etc.

df and ps are also usually external processes. df probably runs too fast for you to catch it (on my system, time df shows it takes 0.003 s to run it), but the output of ps pretty much by necessity also contains the ps process itself, which you can see with e.g. ps -ef |grep ps.

On the other hand, echo and pwd are built in to Bash, which you can tell by running e.g. type echo. It should say echo is a shell builtin. Neither has to be, and they're usually available as /bin/echo and /bin/pwd too (or perhaps /usr/bin/ if your system has separate /bin and /usr/bin). pwd can be external because the current working directory is inherited to child processes. On the other hand, cd can't, because changes to the working directory don't affect the parent process.

You could also have a shell that implements sleep, df, ps, cp and such internally. For example, Busybox contains implementations of all of them. However, the one on my system still forks another process to run sleep (but doesn't seem to do that for df).

3
  • bash has a builtin sleep, but it's not enabled by default. The loadable builtins of bash are also not as mature as in zsh. Not all distributions ship them by default and they're not very well tested. Jan 14, 2021 at 14:37
  • (bash since 4.4 has $BASH_LOADABLES_PATH as an equivalent of zsh's $MODULE_PATH but it's not set by default so one has to know where to find the module files. (it's also imported from the environment!)) Jan 14, 2021 at 14:44
  • ksh93 and mksh have sleep builtin. ksh93 is the one that supports the largest list of duration formats. zsh has zselect. Jan 14, 2021 at 14:45
0

Short answer: because that's the way the system is designed. The people that designed Unix long ago had to make a decision, which commands will be the internal ones (recognized and performed by the shell itself), and which will be the external ones (run via separate binaries/processes).

Some commands, like cd, pwd or set must obviously be internal, as they refer to the shell's internal state, so they cannot be performed by external processes. As for most other commands, the designers had the choice whether the command has to be internal or external - and in fact, there are differences between various shells with regard to this.

For example, there were some old systems/shells where echo was an external command. Nowadays echo is an internal command in almost all shells, however the legacy /bin/echo external command still exists (at least in Linux), probably for compatibility reasons.

As said in the other answer, using the command type (which obviously must be internal command like cd) you can check which commands are internal and which external ones:

raj@rafa:~$ type echo
echo is a shell builtin
raj@rafa:~$ type df
df is hashed (/bin/df)
raj@rafa:~$ type ps
ps is /bin/ps
raj@rafa:~$ 

Note the "df is hashed" message - it means that df command has already been used in this shell session, so the shell remembered it's location and does not have to search for it on the disk again when I want to run it. On the other hand, ps has not been used yet in this session, so the command just shows the path to it.

1
  • 2
    Note that a few shells have sleep builtin. That's the case of at least ksh93 and mksh. bash has a loadable sleep builtin (enable -f /usr/lib/bash/sleep sleep (actual path may vary)). zsh has zselect which can be used for sleeping as well. Jan 14, 2021 at 13:42

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .