Union commands after the || (OR) operator
When I write the code the way below, I am able to run several commands after the else
statement:
if [ "$?" -eq 0 ]
then
echo "OK"
else
echo "NOK"
exit 1
fi
However, when I use another syntax I am unable to union 2 commands after the OR:
[ "$?" -eq 0 ] && echo "OK" || (echo "NOK" >&2 ; exit 1)
In my use-case I have a complex script based on "$?" == 0
, so I'm looking for a way to abort (additionally to echoing the message) when it is not true.
linux command-line test
add a comment |
When I write the code the way below, I am able to run several commands after the else
statement:
if [ "$?" -eq 0 ]
then
echo "OK"
else
echo "NOK"
exit 1
fi
However, when I use another syntax I am unable to union 2 commands after the OR:
[ "$?" -eq 0 ] && echo "OK" || (echo "NOK" >&2 ; exit 1)
In my use-case I have a complex script based on "$?" == 0
, so I'm looking for a way to abort (additionally to echoing the message) when it is not true.
linux command-line test
1
Not that the question isn't a good one, but I'm curious why you are so insistent on avoiding theif
/then
/else
syntax. If you're worried about having to use several lines, it is perfectly possible to make a one-liner of it:if a; then b; else c; fi
– Dolda2000
Dec 24 '18 at 1:51
add a comment |
When I write the code the way below, I am able to run several commands after the else
statement:
if [ "$?" -eq 0 ]
then
echo "OK"
else
echo "NOK"
exit 1
fi
However, when I use another syntax I am unable to union 2 commands after the OR:
[ "$?" -eq 0 ] && echo "OK" || (echo "NOK" >&2 ; exit 1)
In my use-case I have a complex script based on "$?" == 0
, so I'm looking for a way to abort (additionally to echoing the message) when it is not true.
linux command-line test
When I write the code the way below, I am able to run several commands after the else
statement:
if [ "$?" -eq 0 ]
then
echo "OK"
else
echo "NOK"
exit 1
fi
However, when I use another syntax I am unable to union 2 commands after the OR:
[ "$?" -eq 0 ] && echo "OK" || (echo "NOK" >&2 ; exit 1)
In my use-case I have a complex script based on "$?" == 0
, so I'm looking for a way to abort (additionally to echoing the message) when it is not true.
linux command-line test
linux command-line test
edited Dec 30 '18 at 17:42
Jeff Schaller♦
44.4k1162143
44.4k1162143
asked Dec 23 '18 at 9:41
facelessfaceless
424
424
1
Not that the question isn't a good one, but I'm curious why you are so insistent on avoiding theif
/then
/else
syntax. If you're worried about having to use several lines, it is perfectly possible to make a one-liner of it:if a; then b; else c; fi
– Dolda2000
Dec 24 '18 at 1:51
add a comment |
1
Not that the question isn't a good one, but I'm curious why you are so insistent on avoiding theif
/then
/else
syntax. If you're worried about having to use several lines, it is perfectly possible to make a one-liner of it:if a; then b; else c; fi
– Dolda2000
Dec 24 '18 at 1:51
1
1
Not that the question isn't a good one, but I'm curious why you are so insistent on avoiding the
if
/then
/else
syntax. If you're worried about having to use several lines, it is perfectly possible to make a one-liner of it: if a; then b; else c; fi
– Dolda2000
Dec 24 '18 at 1:51
Not that the question isn't a good one, but I'm curious why you are so insistent on avoiding the
if
/then
/else
syntax. If you're worried about having to use several lines, it is perfectly possible to make a one-liner of it: if a; then b; else c; fi
– Dolda2000
Dec 24 '18 at 1:51
add a comment |
3 Answers
3
active
oldest
votes
The pair of (
)
spawns a subshell, defeating the goal of exiting the whole script with the exit command inside.
Just replace the (
)
with {
}
(and adjusted syntax because {
}
are not automatical delimiters but more treated like commands: a space after {
and last command inside must end with some terminator:;
fits): this will run the chain of commands inside in the same shell, thus exit will affect this shell.
[ "$?" -eq 0 ] && echo "OK" || { echo "NOK" >&2; exit 1;}
UPDATE: @D.BenKnoble commented that should echo
fail, the behaviour won't be like the former if ...; then ... else ... fi
construct. So the first echo
's exit code has to be "escaped" with a noop :
command (which being built-in can't fail).
[ "$?" -eq 0 ] && { echo "OK"; :;} || { echo "NOK" >&2; exit 1;}
references:
POSIX:
Grouping Commands
The format for grouping commands is as follows:
(compound-list)
Execute compound-list in a subshell environment; see Shell
Execution Environment. Variable assignments and built-in commands
that affect the environment shall not remain in effect
after the list finishes.
[...]
{ compound-list;}
Execute compound-list in the current process environment. The
semicolon shown here is an example of a control operator delimiting
the } reserved word. Other delimiters are possible, as shown
in Shell Grammar; a <newline> is frequently used.
dash manpage,bash manpage,...
This is NOT guaranteed to work the way you think it will; if echo fails for some reason the script will exit.
– D. Ben Knoble
Dec 23 '18 at 22:00
1
@D.BenKnoble you're right. I was just addressing the obvious, considering echo cannot fail. Addressed it by forcing the exit code of the (now first) compound command.
– A.B
Dec 24 '18 at 1:01
add a comment |
One way would be to use the following script line:
[ "$?" -eq 0 ] && echo "OK" || exit $(echo "NOK" >&2 ; echo 1)
That serves the purpose of reporting an error and returning an error code, whilst being silent if the "OK" path is chosen.
add a comment |
The problem is that you are executing the other branch in a subshell (that is what the parentheses mead - e.g. in bash(1)
man page look for compound commands
) - thus the exit
quits the subshell and not the shell executing the script. To see it more graphically, put a long enough sleep
in both versions of your code, and run ps faux
(for coreutils
version of ps
) or something like pstree
to see the process ancestry relationships.
Now, how to "fix" it:
there's nothing wrong about
if ... then / else / fi
. Especially for longer blocks it makes the code more readable.
if you want a one liner, then you can do
[ "$?" -eq 0 ] && echo "OK" || echo "NOK" >&2 && exit 1
which relies on echo exiting gracefully, or use a group command
[ "$?" -eq 0 ] && echo "OK" || { echo "NOK" >&2 ; exit 1; }
Check for general availability in your shell and for any peculiarities though - e.g. it should be terminated by a newline or a semicolon.
most comprehensive - use a signal/event handler (
bash
example, syntax for other shells might differ):
#!/bin/bash
exit_handler () {
echo "error happened, exiting"
... fix things, that may be half baked ...
}
trap exit_handler EXIT
... do stuff ...
This gives you the opportunity to:
- use
set -e
(set -o errexit
) which is often considered dangerous - theEXIT
handler can do things like removing any temporary files you one doesn't want to leave behind - have the cleanup code in one place only
- handle other signals (those sent by e.g.
kill
) as well
- use
add a comment |
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "106"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: false,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: null,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2funix.stackexchange.com%2fquestions%2f490572%2funion-commands-after-the-or-operator%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
3 Answers
3
active
oldest
votes
3 Answers
3
active
oldest
votes
active
oldest
votes
active
oldest
votes
The pair of (
)
spawns a subshell, defeating the goal of exiting the whole script with the exit command inside.
Just replace the (
)
with {
}
(and adjusted syntax because {
}
are not automatical delimiters but more treated like commands: a space after {
and last command inside must end with some terminator:;
fits): this will run the chain of commands inside in the same shell, thus exit will affect this shell.
[ "$?" -eq 0 ] && echo "OK" || { echo "NOK" >&2; exit 1;}
UPDATE: @D.BenKnoble commented that should echo
fail, the behaviour won't be like the former if ...; then ... else ... fi
construct. So the first echo
's exit code has to be "escaped" with a noop :
command (which being built-in can't fail).
[ "$?" -eq 0 ] && { echo "OK"; :;} || { echo "NOK" >&2; exit 1;}
references:
POSIX:
Grouping Commands
The format for grouping commands is as follows:
(compound-list)
Execute compound-list in a subshell environment; see Shell
Execution Environment. Variable assignments and built-in commands
that affect the environment shall not remain in effect
after the list finishes.
[...]
{ compound-list;}
Execute compound-list in the current process environment. The
semicolon shown here is an example of a control operator delimiting
the } reserved word. Other delimiters are possible, as shown
in Shell Grammar; a <newline> is frequently used.
dash manpage,bash manpage,...
This is NOT guaranteed to work the way you think it will; if echo fails for some reason the script will exit.
– D. Ben Knoble
Dec 23 '18 at 22:00
1
@D.BenKnoble you're right. I was just addressing the obvious, considering echo cannot fail. Addressed it by forcing the exit code of the (now first) compound command.
– A.B
Dec 24 '18 at 1:01
add a comment |
The pair of (
)
spawns a subshell, defeating the goal of exiting the whole script with the exit command inside.
Just replace the (
)
with {
}
(and adjusted syntax because {
}
are not automatical delimiters but more treated like commands: a space after {
and last command inside must end with some terminator:;
fits): this will run the chain of commands inside in the same shell, thus exit will affect this shell.
[ "$?" -eq 0 ] && echo "OK" || { echo "NOK" >&2; exit 1;}
UPDATE: @D.BenKnoble commented that should echo
fail, the behaviour won't be like the former if ...; then ... else ... fi
construct. So the first echo
's exit code has to be "escaped" with a noop :
command (which being built-in can't fail).
[ "$?" -eq 0 ] && { echo "OK"; :;} || { echo "NOK" >&2; exit 1;}
references:
POSIX:
Grouping Commands
The format for grouping commands is as follows:
(compound-list)
Execute compound-list in a subshell environment; see Shell
Execution Environment. Variable assignments and built-in commands
that affect the environment shall not remain in effect
after the list finishes.
[...]
{ compound-list;}
Execute compound-list in the current process environment. The
semicolon shown here is an example of a control operator delimiting
the } reserved word. Other delimiters are possible, as shown
in Shell Grammar; a <newline> is frequently used.
dash manpage,bash manpage,...
This is NOT guaranteed to work the way you think it will; if echo fails for some reason the script will exit.
– D. Ben Knoble
Dec 23 '18 at 22:00
1
@D.BenKnoble you're right. I was just addressing the obvious, considering echo cannot fail. Addressed it by forcing the exit code of the (now first) compound command.
– A.B
Dec 24 '18 at 1:01
add a comment |
The pair of (
)
spawns a subshell, defeating the goal of exiting the whole script with the exit command inside.
Just replace the (
)
with {
}
(and adjusted syntax because {
}
are not automatical delimiters but more treated like commands: a space after {
and last command inside must end with some terminator:;
fits): this will run the chain of commands inside in the same shell, thus exit will affect this shell.
[ "$?" -eq 0 ] && echo "OK" || { echo "NOK" >&2; exit 1;}
UPDATE: @D.BenKnoble commented that should echo
fail, the behaviour won't be like the former if ...; then ... else ... fi
construct. So the first echo
's exit code has to be "escaped" with a noop :
command (which being built-in can't fail).
[ "$?" -eq 0 ] && { echo "OK"; :;} || { echo "NOK" >&2; exit 1;}
references:
POSIX:
Grouping Commands
The format for grouping commands is as follows:
(compound-list)
Execute compound-list in a subshell environment; see Shell
Execution Environment. Variable assignments and built-in commands
that affect the environment shall not remain in effect
after the list finishes.
[...]
{ compound-list;}
Execute compound-list in the current process environment. The
semicolon shown here is an example of a control operator delimiting
the } reserved word. Other delimiters are possible, as shown
in Shell Grammar; a <newline> is frequently used.
dash manpage,bash manpage,...
The pair of (
)
spawns a subshell, defeating the goal of exiting the whole script with the exit command inside.
Just replace the (
)
with {
}
(and adjusted syntax because {
}
are not automatical delimiters but more treated like commands: a space after {
and last command inside must end with some terminator:;
fits): this will run the chain of commands inside in the same shell, thus exit will affect this shell.
[ "$?" -eq 0 ] && echo "OK" || { echo "NOK" >&2; exit 1;}
UPDATE: @D.BenKnoble commented that should echo
fail, the behaviour won't be like the former if ...; then ... else ... fi
construct. So the first echo
's exit code has to be "escaped" with a noop :
command (which being built-in can't fail).
[ "$?" -eq 0 ] && { echo "OK"; :;} || { echo "NOK" >&2; exit 1;}
references:
POSIX:
Grouping Commands
The format for grouping commands is as follows:
(compound-list)
Execute compound-list in a subshell environment; see Shell
Execution Environment. Variable assignments and built-in commands
that affect the environment shall not remain in effect
after the list finishes.
[...]
{ compound-list;}
Execute compound-list in the current process environment. The
semicolon shown here is an example of a control operator delimiting
the } reserved word. Other delimiters are possible, as shown
in Shell Grammar; a <newline> is frequently used.
dash manpage,bash manpage,...
edited Dec 24 '18 at 1:08
answered Dec 23 '18 at 10:33
A.BA.B
5,7621830
5,7621830
This is NOT guaranteed to work the way you think it will; if echo fails for some reason the script will exit.
– D. Ben Knoble
Dec 23 '18 at 22:00
1
@D.BenKnoble you're right. I was just addressing the obvious, considering echo cannot fail. Addressed it by forcing the exit code of the (now first) compound command.
– A.B
Dec 24 '18 at 1:01
add a comment |
This is NOT guaranteed to work the way you think it will; if echo fails for some reason the script will exit.
– D. Ben Knoble
Dec 23 '18 at 22:00
1
@D.BenKnoble you're right. I was just addressing the obvious, considering echo cannot fail. Addressed it by forcing the exit code of the (now first) compound command.
– A.B
Dec 24 '18 at 1:01
This is NOT guaranteed to work the way you think it will; if echo fails for some reason the script will exit.
– D. Ben Knoble
Dec 23 '18 at 22:00
This is NOT guaranteed to work the way you think it will; if echo fails for some reason the script will exit.
– D. Ben Knoble
Dec 23 '18 at 22:00
1
1
@D.BenKnoble you're right. I was just addressing the obvious, considering echo cannot fail. Addressed it by forcing the exit code of the (now first) compound command.
– A.B
Dec 24 '18 at 1:01
@D.BenKnoble you're right. I was just addressing the obvious, considering echo cannot fail. Addressed it by forcing the exit code of the (now first) compound command.
– A.B
Dec 24 '18 at 1:01
add a comment |
One way would be to use the following script line:
[ "$?" -eq 0 ] && echo "OK" || exit $(echo "NOK" >&2 ; echo 1)
That serves the purpose of reporting an error and returning an error code, whilst being silent if the "OK" path is chosen.
add a comment |
One way would be to use the following script line:
[ "$?" -eq 0 ] && echo "OK" || exit $(echo "NOK" >&2 ; echo 1)
That serves the purpose of reporting an error and returning an error code, whilst being silent if the "OK" path is chosen.
add a comment |
One way would be to use the following script line:
[ "$?" -eq 0 ] && echo "OK" || exit $(echo "NOK" >&2 ; echo 1)
That serves the purpose of reporting an error and returning an error code, whilst being silent if the "OK" path is chosen.
One way would be to use the following script line:
[ "$?" -eq 0 ] && echo "OK" || exit $(echo "NOK" >&2 ; echo 1)
That serves the purpose of reporting an error and returning an error code, whilst being silent if the "OK" path is chosen.
answered Dec 23 '18 at 9:57
Ralph RönnquistRalph Rönnquist
2,70759
2,70759
add a comment |
add a comment |
The problem is that you are executing the other branch in a subshell (that is what the parentheses mead - e.g. in bash(1)
man page look for compound commands
) - thus the exit
quits the subshell and not the shell executing the script. To see it more graphically, put a long enough sleep
in both versions of your code, and run ps faux
(for coreutils
version of ps
) or something like pstree
to see the process ancestry relationships.
Now, how to "fix" it:
there's nothing wrong about
if ... then / else / fi
. Especially for longer blocks it makes the code more readable.
if you want a one liner, then you can do
[ "$?" -eq 0 ] && echo "OK" || echo "NOK" >&2 && exit 1
which relies on echo exiting gracefully, or use a group command
[ "$?" -eq 0 ] && echo "OK" || { echo "NOK" >&2 ; exit 1; }
Check for general availability in your shell and for any peculiarities though - e.g. it should be terminated by a newline or a semicolon.
most comprehensive - use a signal/event handler (
bash
example, syntax for other shells might differ):
#!/bin/bash
exit_handler () {
echo "error happened, exiting"
... fix things, that may be half baked ...
}
trap exit_handler EXIT
... do stuff ...
This gives you the opportunity to:
- use
set -e
(set -o errexit
) which is often considered dangerous - theEXIT
handler can do things like removing any temporary files you one doesn't want to leave behind - have the cleanup code in one place only
- handle other signals (those sent by e.g.
kill
) as well
- use
add a comment |
The problem is that you are executing the other branch in a subshell (that is what the parentheses mead - e.g. in bash(1)
man page look for compound commands
) - thus the exit
quits the subshell and not the shell executing the script. To see it more graphically, put a long enough sleep
in both versions of your code, and run ps faux
(for coreutils
version of ps
) or something like pstree
to see the process ancestry relationships.
Now, how to "fix" it:
there's nothing wrong about
if ... then / else / fi
. Especially for longer blocks it makes the code more readable.
if you want a one liner, then you can do
[ "$?" -eq 0 ] && echo "OK" || echo "NOK" >&2 && exit 1
which relies on echo exiting gracefully, or use a group command
[ "$?" -eq 0 ] && echo "OK" || { echo "NOK" >&2 ; exit 1; }
Check for general availability in your shell and for any peculiarities though - e.g. it should be terminated by a newline or a semicolon.
most comprehensive - use a signal/event handler (
bash
example, syntax for other shells might differ):
#!/bin/bash
exit_handler () {
echo "error happened, exiting"
... fix things, that may be half baked ...
}
trap exit_handler EXIT
... do stuff ...
This gives you the opportunity to:
- use
set -e
(set -o errexit
) which is often considered dangerous - theEXIT
handler can do things like removing any temporary files you one doesn't want to leave behind - have the cleanup code in one place only
- handle other signals (those sent by e.g.
kill
) as well
- use
add a comment |
The problem is that you are executing the other branch in a subshell (that is what the parentheses mead - e.g. in bash(1)
man page look for compound commands
) - thus the exit
quits the subshell and not the shell executing the script. To see it more graphically, put a long enough sleep
in both versions of your code, and run ps faux
(for coreutils
version of ps
) or something like pstree
to see the process ancestry relationships.
Now, how to "fix" it:
there's nothing wrong about
if ... then / else / fi
. Especially for longer blocks it makes the code more readable.
if you want a one liner, then you can do
[ "$?" -eq 0 ] && echo "OK" || echo "NOK" >&2 && exit 1
which relies on echo exiting gracefully, or use a group command
[ "$?" -eq 0 ] && echo "OK" || { echo "NOK" >&2 ; exit 1; }
Check for general availability in your shell and for any peculiarities though - e.g. it should be terminated by a newline or a semicolon.
most comprehensive - use a signal/event handler (
bash
example, syntax for other shells might differ):
#!/bin/bash
exit_handler () {
echo "error happened, exiting"
... fix things, that may be half baked ...
}
trap exit_handler EXIT
... do stuff ...
This gives you the opportunity to:
- use
set -e
(set -o errexit
) which is often considered dangerous - theEXIT
handler can do things like removing any temporary files you one doesn't want to leave behind - have the cleanup code in one place only
- handle other signals (those sent by e.g.
kill
) as well
- use
The problem is that you are executing the other branch in a subshell (that is what the parentheses mead - e.g. in bash(1)
man page look for compound commands
) - thus the exit
quits the subshell and not the shell executing the script. To see it more graphically, put a long enough sleep
in both versions of your code, and run ps faux
(for coreutils
version of ps
) or something like pstree
to see the process ancestry relationships.
Now, how to "fix" it:
there's nothing wrong about
if ... then / else / fi
. Especially for longer blocks it makes the code more readable.
if you want a one liner, then you can do
[ "$?" -eq 0 ] && echo "OK" || echo "NOK" >&2 && exit 1
which relies on echo exiting gracefully, or use a group command
[ "$?" -eq 0 ] && echo "OK" || { echo "NOK" >&2 ; exit 1; }
Check for general availability in your shell and for any peculiarities though - e.g. it should be terminated by a newline or a semicolon.
most comprehensive - use a signal/event handler (
bash
example, syntax for other shells might differ):
#!/bin/bash
exit_handler () {
echo "error happened, exiting"
... fix things, that may be half baked ...
}
trap exit_handler EXIT
... do stuff ...
This gives you the opportunity to:
- use
set -e
(set -o errexit
) which is often considered dangerous - theEXIT
handler can do things like removing any temporary files you one doesn't want to leave behind - have the cleanup code in one place only
- handle other signals (those sent by e.g.
kill
) as well
- use
edited Dec 23 '18 at 11:05
answered Dec 23 '18 at 10:51
peterphpeterph
23.8k24558
23.8k24558
add a comment |
add a comment |
Thanks for contributing an answer to Unix & Linux Stack Exchange!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2funix.stackexchange.com%2fquestions%2f490572%2funion-commands-after-the-or-operator%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
1
Not that the question isn't a good one, but I'm curious why you are so insistent on avoiding the
if
/then
/else
syntax. If you're worried about having to use several lines, it is perfectly possible to make a one-liner of it:if a; then b; else c; fi
– Dolda2000
Dec 24 '18 at 1:51