Background processing and job control
Although the shell might seem one-dimensional, in fact you can run many different jobs at the same time. For instance, say you wanted to run a program that you knew would take a long time to complete, and you had other things to do in the shell session in the meantime -- no need to just sit and wait. Rather, tell Bash to run the process in the background. You do this by adding an ampersand after the command line:
[myname@lab1 ~]$ ./longprocess.bin &
The response below the command is Bash's notification that you've started job No. 1, and its process ID is 3104. The process will continue to run in the background until it completes. When it's done, Bash will let you know:
+ Done ./longprocess.bin
If you had not added the
& when you ran
longprocess.bin, you would not get a Bash prompt back until the job completed.
You can bring a background job back into the foreground by using the
fg command. Likewise, you can place a foreground job into the background by using the
bg command. You can stop a process that's running in the foreground by hitting Ctrl-Z, then place it in the background by entering
[myname@lab1 ~]$ ./longprocess.bin
+ Stopped ./longprocess.bin
[myname@lab1 ~]$ bg %1
You can view a list of running jobs by using the
[myname@lab1 ~]$ jobs
+ Running ./longprocess1.bin
+ Running ./longprocess2.bin -afG
+ Running ./longprocess3.bin -rT
You can use the
fg command to bring one of them back into the foreground:
[myname@lab1 ~]$ fg %1
Note that any output produced by background processes will be shown in the shell, which can get messy if there's a lot of it. Fortunately, we can use our operators to tell Bash to send the output to
/dev/null, which will prevent it from displaying in our session:
[myname@lab1 ~]$ ./longprocess1.bin > /dev/null &
This will still show us error messages sent to stderr, but not output sent to stdout. If we wanted to redirect stderr as well, we would type this:
[myname@lab1 ~]$ ./longprocess1.bin > /dev/null 2>&1 &
This tells Bash to send stderr (2) to the same place as stdout (1).
One of the major functions that Bash provides is the ability to run commands in a loop. Loops allow you to quickly perform many functions on a file or set of files or just for general output.
For instance, you might use a loop to systematically and, very quickly, rename a large number of files. Let's say we have a directory full of files like so:
These files have served their purpose, and now we need to rename each of them to Info#.txt.old. Rather than manually typing in each name and using the
move) command, we would be better off using a
for i in 'ls *.txt'; do mv $i $i.old; done
This is a very simple one-line loop command that will rename all the files ending in .txt to their original name with .old appended at the end. Thus, our files are now named Info1.txt.old, Info2.txt.old, and so forth.
What this loop is doing is using the output of the
ls *.txt command as a list of file names, which is represented by the variable
$i. Bash will take each file name at a time, then run the
mv $i $i.old command, replacing the variable with the actual filename.