Consider warning about echo containing a backslash when the shell is /bin/sh
For bugs
- Rule ID: SC2028
- My shellcheck version: online
- [x] The rule's wiki page does not already cover this entirely
- [x] I tried on https://www.shellcheck.net/
Here's a snippet or screenshot that shows the problem:
#!/bin/sh
echo '\\ output depends on shell'
# bash: \\ output depends on shell
# coreutils: \\ output depends on shell
# dash: \ output depends on shell
Here's what shellcheck currently says:
Line 2:
echo '\\ output depends on shell'
^-- SC2028 (info): echo may not expand escape sequences. Use printf.
Here's what I wanted or expected to see:
The info message and advice is useful already, but I think that it is too weak for some situations. If you try an echo in different shells, you shall see that
bashwill echo back the unescaped string (unless adding-e)./bin/echofromcoreutilslikewise.dashwill unescape the string. If passing-e, it will echo-eas well. See also https://bugs.debian.org/538100
Thus the behaviour of this code is dependent on the shell. As such I would like to see a severity warning message from shellcheck (if and only if the shell is specified as sh).
Furthermore, the wiki page advises to use echo "\\t" to get a literal backslash t. Notably, on dash this actually outputs a tab. I think this advice should be changed to printf "\\t".
I am unsure whether this should be an extension to SC2028 or a new rule, but I hope you see the problem.
In essence, I'd like to get a warning whenever the shell is sh and an argument to echo involves a literal backslash. It is questionable whether there also should be a warning when echo is used to output a variable (which may contain a backslash of its own). For concrete shells, depending on the particular shell behaviour seems fine to me.
I'm not sure I quite follow.
Without -e, all 3 cases return the unescaped string right?
Maybe checking only if -e is passed would be appropiate in that case.
I'm more in favor of encouraging printf usage for this.
Thank you for following up. As surprising as it may sound, dash echo will always unescape regardless of whether you specify -e or not. If you also pass -e it will echo that and -e does not affect escaping. It is not considered an option.
This behavior of dash is the primary reason for me filing this issue. If it were not unconditionally unescaping, I would not have reported this.
https://github.com/SwuduSusuwu/SubStack/issues/47 has to do with this; the problem was that the SC2028 info message does not show if you have
#!/bin/sh
echo "\033[34m Coded blue"
, which results in color codes which /bin/sh shows but which break (which print literal escape sequences) if you switch to #!/bin/bash (or if you have a system where /bin/sh points to /bin/bash, although such is perhaps not a POSIX system).
Such should not produce a warning (as such is valid for POSIX /bin/sh), but is odd that such does not produce a notice or info message.