Command chaining: Inline or Already running process


Overview

You may sometimes want to run several commands sequentially in Linux. To accomplish this, you can use command chaining. For example, if you wanted to download a compressed archive, decompress it, and then remove the resulting archive from disk, you could type these three commands together.

Here, we’ll look at some methods for serializing commands using Bash in Linux. Even if they're already running.

Inline Command Chaining

Bash has great flexibility and powerful features for the end−users. We can create long sequences of instructions to perform any number of tasks.

<command1> <arguments1> <chaining operator> <command2> <arguments2> ...

Chained operations include several common ones, so we’ll take a look at them here.

  • ; (semicolon) − The command on the far right always runs after the one on the near right, even if the latter fails.

  • & (ampersand) − On the left side, there is a "run in the backgroud" option; on the right side, there is an "immediatly start" option.

  • | (pipe) − The left command‘s standard out pipes into the right command's standard input

  • && (AND) − If the command on the right succeeds, then execute the command on the right. Otherwise, don't execute the command on the riht.

  • || (OR) − If the one on the left executed successfully (a zero returned), then execute the one on the right.

You can also enclose statements within parentheses to execute them in a subshell.

( <command1> && <command2> ) & ( <command3> && <command4> ) &

These two commands would be executed one after another. In each, the second result condition the last.

Command Chaining with Already Running Processes

We'll look at how we can use the Wait() function to execute a second shell script after one has already been started. This is a wrapper for the syscall called Wait().

When run without any parameters, it waits for all background processes of the current shell. If no parameters are given, it will hang the shell until all processes are completed.

You can use the pidsof command to get the process IDs (PIDs) of all running processes with similar names. Let’s say we want to run three background 10-sec sleep commands and then check which ones were successful. We could type −

$ sleep 10 &
[1] 26176

$ sleep 10 &
[2] 26178

$ sleep 10 &
[3] 26179

$ wait $(pidof sleep) && echo Waited for 3 10-second sleeps
[1]     Done          sleep 10
[2]-    Done          sleep 10
[3]+    Done          sleep 10
Waited for 3 10-second sleeps

You could achieve the same results by combining several commands into one. For example, you could use the following sequence of commands:ps -ef | grep -v 'string'.

$ wait $(ps -ef | grep <process name> | tr -s ' ' | cut -f 2 -d ' ' ) && echo Waited for 3 10-second sleeps

Command chains show another way of chaining together multiple actions. The $() function tells us that the output from the code inside the parentheses will be used as a parameter for the wait function. In our case −

  • ps −ef − gathers all processes with details

  • grep <process name> − selects from the ps −ef output the lines containing <process name>

  • tr −s ‘ ‘ − remove, from grep‘s output any duplicated occurrences of ‘ ‘ (space)

  • cut −d ‘ ‘ −f 2 − Select from tr output the second column by specifying the space character as the delimiter. For example, if we list all the processes running on our system using ps −ef | grep java, then filter out just the ones whose parent PID matches the one from previous step.

Limitations of the wait Command

For the WAITTEST_TIMEOUT variable, WAITTIME returns the time since the program started waiting for the specified command. However, it is unreliable if we rely on the PID of an already completed command, for example, it cannot return its real results. If the error code returned by an app is greater than 128, there's no way to tell whether the app terminated because of a signal or on its' own.

Finally, one limitation of `sleep` is that it can only sleep for processes started on the same shell. If we need to run processes of other users or open in other shells, we'll have to use other less straightforward methods like a pidof loop.

while ( pidof -q <command_to_wait> ); do sleep 1; done && <command_to_execute_after>

Wait is a more general and less powerful alternative to sleep. It depends on a specific sleeping period and cannot evaluate the result of the targeted operation. It's important to use sleep between iterations on shell scripts because it gives back CPU time to the system. Especially if the script ends too quickly.

Conclusion

We've seen some common uses of command changing in shell scripts− both inline and waiting until another script finishes before continuing. There are even more options and greater flexibility available. You can use these techniques to create scripts, functions, conditions, or loops.

Updated on: 26-Dec-2022

147 Views

Kickstart Your Career

Get certified by completing the course

Get Started
Advertisements