Issue
I'm sure this has been asked but my search has been fruitless.
I want to run 3 bash commands in order with both the second and third only running if the first succeeded.
Example:
## Setup
mkdir so_test_tmp && cd so_test_tmp
echo "This is something" > something
cd ..
## Example commands
cd so_test_tmp ??? cat nothing ??? cd .. # 0.
cd so_test_tmp ??? cat something ??? cd .. # 1.
cd does_not_exist ??? cat nothing ??? cd .. # 2.
These three commands should always end in PWD. In 0.
the first cd is run, then the last. In 1.
all three commands successfully run. In 2.
the first command fails so the second and third are not run.
Solution
Specifically for cd somewhere && somecommand && cd ..
The cd ..
is only necessary because you're doing cd so_test_tmp
inside your parent shell, as opposed to the subshell that's fork()
ed off to then be replaced with a copy of /bin/cat
.
By creating an explicit subshell with ( ... )
, you can scope the cd
to its contents. By using exec
for the last command in the subshell, you can consume it, balancing out the performance overhead of that subshell's creation.
(cd so_test_tmp && exec cat nothing) # 0.
(cd so_test_tmp && exec cat something) # 1.
(cd does_not_exist && exec cat nothing) # 2.
Note that this applies only when the command you're running in a subdirectory doesn't change the state of the shell that started it (like setting a variable). If you need to set a variable, you might instead want something like output=$(cd /to/directory && exec some_command)
.
Answering the more general question
Use &&
to connect the first command to a group with the second and third commands, and use ;
to combine those 2nd and 3rd commands, if your goal is to ensure that both 2nd and 3rd run if-and-only-if the 1st succeeds.
cd so_test_tmp && { cat nothing; cd ..; } # 0.
cd so_test_tmp && { cat something; cd ..; } # 1.
cd does_not_exist && { cat nothing; cd ..; } # 2.
Answered By - Charles Duffy