13 SC1010
wileyhy edited this page 2024-10-05 23:47:39 -07:00

Use semicolon or linefeed before done (or quote to make it literal).

(or do then, fi, esac)

Problematic code:

for f in *; do echo "$f" done

or

echo $f is done

Correct code:

for f in *; do echo "$f"; done

or

echo "$f is done"

Rationale:

ShellCheck found a keyword like done, then, fi, esac, etc used as the argument of a command. This means that the shell will interpret it as a literal string rather than a shell keyword. To be interpreted as a keyword, it must be the first word in the line (i.e. after ;, & or a linefeed).

In the example, echo "$f" done is the same as echo "$f" "done", and the done does not terminate the loop. This is fixed by terminating the echo command with a ; so that the done is the first word in the next line.

Exceptions

If you're intentionally using done as a literal, you can quote it to make this clear to ShellCheck (and also human readers), e.g. instead of echo Task is done, use echo "Task is done". This makes no difference to the shell, but it will silence this warning.

From POSIX-2018, section "C.2.10 Shell Grammar," regarding the syntax, if (false) then (echo x) else (echo y) fi: https://pubs.opengroup.org/onlinepubs/9699919799/xrat/V4_xcu_chap02.html#tag_23_02_10