Why combine commands on a single line in a Bash script?

mkdir build && cd build && touch blank.txt

In Bash (and some other shells) && is a logical and, which means - if the previous command returns true the next command will be executed. There is also logical or ||. For example you can combine these two options in one statement:

mkdir /tmp/abc/123 && echo 'the dir is created' || echo "the dir isn't created"

Note, the construction cmd_1 && cmd_2 || comd_3 is not a substitute of the if; then; else statement, because no matter which of the preceding commands return false, the cmd_3 will be executed. So you must be careful about the circumstances in which you are using it. Here is an example:

$ true && false || echo success
success
$ false && true || echo success
success
$ false && false || echo success
success

As a rule rule of thumb, usually, when I'm using the cd command within a script, I'm putting a test whether the directory change is successful: cd somewhere/ || exit. More proper test is proposed by @dessert: if ! cd dir; then exit 1; fi. But in all cases as protection of script's failure it is better to use the set -e option as it is shown in the @mrks' answer.


mkdir build; cd build; touch blank.txt

; is a line delimiter and it is used when few separated commands are written in one line.


Note when ; or && and || are in use it is not mandatory to write the commands at on line - this is illustrated within the @allo's answer.

At all, IMO, there is not any special technical advantage/difference between writing the commands at one or at separate lines.


COMMAND="mkdir build && cd build && touch blank.txt"
eval ${COMMAND}

Here one or more commands (and their arguments) are grouped as value of a variable, and then this variable (argument) is converted to a command by the help of eval. Thus you will be able to change the command that will be executed multiple times within some script by changing it at only one place.

Let's say you need to change the way in which the file blank.txt is created, for example, you can change the relevant line in a way as this:

COMMAND="mkdir build && cd build && echo 'test' > blank.txt"

The actual eval's advantage over the usage of alias is when there re-directions, pipes, logical operators, etc. are in use.

In most cases you can use functions instead of eval when alias is not applicable. Also in case the variable contains only a single command, i.e. CMD="cat", we do not need eval, because Bash world-split will expand "$CMD" "$file1" "$file2" correctly.

  • Here is one example where eval was the simplest way to do some command automation: Tail the “in the last hour written lines from a log file” is it possible?

  • The previous version of this section, discussed within the comments is available here.


The answers so far address what happens/how it works but I think you were asking "why"

The main "Reason" to do it (for me) rather than typing them on three lines is that sometimes the commands take time (Sometimes minutes) and you don't want to hang out for the whole time.

For example, I might build && deploy && start my app then head out for lunch. The process could take 15 minutes to complete. However since I used &&, it won't deploy if the build fails--so that works.

Type-ahead is an alternative but it is iffy, you might not be able to see what you type (and therefore make mistakes) or a program might eat the type-ahead (Thanks, grails!). Then you come back from lunch and find out that you still have two longish tasks to kick off because of a typo.

The other alternative is writing a small script or alias. Not a bad idea but doesn't allow as much flexibility, like I can:

stop && build && test && deploy && start 

or I can just:

stop && start

Or any number of other combinations that would quickly pollute a script with bunches of flags.

Even if you do write a script you are likely to integrate it with other scripts with &&.


Combining commands on Linux can be very useful.

A good example may be restarting a remote network interface via ssh (if you've changed network configuration or something...).

ifdown eth0 && ifup eth0

This can prevent you from going physically to the server in order to bring up the interface you where originally ssh'ing to. (You will not be able execute ifup eth0 if ifdown eth0 is executed alone.)