问题
I've read in multiple articles that semicolon(;
) in UNIX-like shells is equal to a new line.
However, the following is confusing me and I'm having no luck googling it either.
I'm guessing it's an issue with do
in shell, but "bash semicolon do" is not exactly the most google-friendly search term combination.
Below is a simple for
statement.
for i in {1..10}
do
echo "hi"
echo "bye"
done
As many Stack Overflow gurus have posted, every newline can be substituted with semicolons.
So.. we have this following "same" statement.
for i in {1..10}; do; echo "hi"; echo "bye"; done
and we get:
-bash: syntax error near unexpected token `;'
What exactly is the semicolon? Is this just an unique issue with do
?
回答1:
Looking at the syntax of the for/do loop,
for name [ [in [words …] ] ; ] do commands; done
we can see that do
is followed by commands
immediately, so using a newline after do
doesn't replace a semicolon, but a space.
The description for compound commands also says
In most cases a list of commands in a compound command’s description may be separated from the rest of the command by one or more newlines, and may be followed by a newline in place of a semicolon.
but nowhere does it say that you can insert random semicolons. "Every newline can be substituted with semicolons" is simply too general a statement and not correct.
More manual evidence: in the section about lists of commands, it says (emphasis mine):
A
list
is a sequence of one or more pipelines separated by one of the operators;
,&
,&&
, or||
, and optionally terminated by one of;
,&
, or anewline
.Of these list operators,
&&
and||
have equal precedence, followed by;
and&
, which have equal precedence.A sequence of one or more newlines may appear in a
list
to delimit commands, equivalent to a semicolon.
So a newline is equivalent to a semicolon within a list of commands.
回答2:
It's not just with do
; there are a number of contexts where the shell allows a newline where it would not allow a semicolon.
Here are most of them (leaving out the uses of newlines or semicolons inside quotes, which are always distinct from each other):
After
&&
or||
some_command && some_other_command
After a pipe (
|
):some_producer | some_consumer
Before the
in
in afor
statement:for x in $(produce_values); do
Although empty commands are illegal, the shell grammar does allow empty value lists in a
for
command, sofor x in; do do_something; done
is legal, and so would be the same thing written with newlines instead of semicolons.Before or after the
in
in acase
statement; also after the closing)
of each pattern and the;;
which closes each case:case $x in pattern) do_something ;; esac
After the keywords
if
,then
,elif
,else
,while
oruntil
:if some_condition then do_something else do_something_else fi
After the
{
or(
which opens a compound command or subshell:{ a_command another_command } ( a_command another_command )
Similarly, after the
$(
which starts a command substitution:a=$( echo hello )
In bash, this also applies to the
(
in process substitution:<(...)
. See below for the slightly different handling in the bash extensions dealing with conditionals and arithmetic substitution.After the
)
in a function definition:my_function() { do_something }
After the
;
or&
which terminates a command:do_something; do_something_in_background &
(Note that empty commands are illegal, so
do_something; ;
would be rejected.)
I took that list from the shell grammar in the Posix standard. Bash allows newlines in other places; I couldn't think of any when I wrote this answer, but @BenjaminW reminded me:
Inside a parenthesized array literal, either in an array assignment or an array declaration, newlines are considered whitespace:
a+=( first_thing second_thing ) local -A b=( [x]="value of x" [y]="value of y" )
And then I remembered these other pseudo-quoted environments:
Bash also accepts newlines as whitespace inside arithmetic expressions:
i=$(( i + 3 * j )) if (( i + 3 * j > 9 ))
and after the
[[
or before the]]
in[[
-style conditional statements:if [[ $a -eq "done" ]] then break fi
来源:https://stackoverflow.com/questions/51034076/bash-semicolon-being-equal-to-newline-is-not-exactly-true