{"id":245,"date":"2013-06-30T17:28:22","date_gmt":"2013-06-30T17:28:22","guid":{"rendered":"http:\/\/www.vidarholen.net\/contents\/blog\/?p=245"},"modified":"2013-07-01T01:43:16","modified_gmt":"2013-07-01T01:43:16","slug":"paste-shell-script-get-feedback-shellcheck-project-update","status":"publish","type":"post","link":"https:\/\/www.vidarholen.net\/contents\/blog\/?p=245","title":{"rendered":"Paste shell script, get feedback: ShellCheck project update"},"content":{"rendered":"<p>tl;dr: <a href=\"http:\/\/www.shellcheck.net\">ShellCheck<\/a> is a bash\/sh static analysis and linting tool. Paste a shell command or script on <a href=\"http:\/\/www.shellcheck.net\">ShellCheck.net<\/a> and get feedback about many common issues, both in scripts that currently fail and scripts that appear to work just fine.<\/p>\n<p>There&#8217;s been a lot of progress since I <a href=\"\/contents\/blog\/?p=221\">first posted<\/a> about it seven months ago. It has a new home on <a href=\"http:\/\/www.shellcheck.net\/\">ShellCheck.net<\/a> with a simplified and improved interface, and the parser has been significantly bugfixed so that parsing errors for correct code are now fairly rare. <\/p>\n<p>However, the best thing is that it can detect a heaping bunch of new problems! This post mentions merely a subset of them.<\/p>\n<p>&nbsp;<br \/> <br \/>\n<strong>Quiz: ShellCheck is aware of many common usage problems. Are you?<\/strong><\/p>\n<ul>\n<li><code>find . -name *.mp3<\/code>\n<li><code>sudo echo 3 > \/proc\/sys\/vm\/drop_caches<\/code>\n<li><code>PS1='\\e[0;32m\\$\\e[0m '<\/code><\/li>\n<li><code>find . | grep \"*.mp3\"<\/code><\/li>\n<li><code>[ $n &gt; 7 ]<\/code><\/li>\n<li><code>[[ $n &gt; 7 ]]<\/code><\/li>\n<li><code>tr 'A-Z' 'a-z'<\/code><\/li>\n<li><code>cmd 2&gt;&1 &gt; log<\/code><\/li>\n<li><code>array=(1, 2, 3)<\/code><\/li>\n<li><code>echo $10<\/code><\/li>\n<li><code>[[ $a=$b ]]<\/code><\/li>\n<li><code>[[ $a = $b ]]<\/code><\/li>\n<li><code>progress=$((i\/total*100))<\/code><\/li>\n<li><code>trap \"echo \\\"Time used: $SECONDS\\\"\" EXIT<\/code><\/li>\n<li><code>find dir -exec cp {} \/backup && rm {} \\;<\/code><\/li>\n<li><code>[[ $keep = [yY] ]] && mv file \/backup || rm file<\/code><\/li>\n<\/ul>\n<p>&nbsp;<br \/> &nbsp; <br \/>\n<strong>ShellCheck gives more helpful messages for many Bash syntax errors<\/strong><\/p>\n<table>\n<tr>\n<th>Bash says<\/th>\n<th>ShellCheck points to the exact position and says<\/th>\n<\/tr>\n<tr>\n<td>: command not found<\/td>\n<td>Literal carriage return. Run script through tr -d &#8216;\\r&#8217;<\/td>\n<\/tr>\n<tr>\n<td>unexpected token: `fi&#8217;<\/td>\n<td>Can&#8217;t have empty then clauses (use &#8216;true&#8217; as a no-op)<\/td>\n<\/tr>\n<tr>\n<td>unexpected token `(&#8216;<\/td>\n<td>Shells are space sensitive. Use &#8216;< <(cmd)', not '<<(cmd)'<\/td>\n<\/tr>\n<tr>\n<td>unexpected token `(&#8216;<\/td>\n<td>&#8216;(&#8216; is invalid here. Did you forget to escape it?<\/td>\n<\/tr>\n<tr>\n<td>echo foo: command not found<\/td>\n<td>This is a &amp;nbsp;. Delete it and retype as space.<\/td>\n<\/tr>\n<\/table>\n<p>&nbsp;<br \/> &nbsp; <br \/>\n<strong>ShellCheck suggests style improvements<\/strong><\/p>\n<table>\n<tr>\n<th>Code<\/th>\n<th>ShellCheck suggestion<\/th>\n<\/tr>\n<tr>\n<td><code>basename \"$var\"<\/code><\/td>\n<td>Use parameter expansion instead, such as ${var##*\/}<\/td>\n<\/tr>\n<tr>\n<td><code>ls | grep 'mp3$'<\/code><\/td>\n<td>Don&#8217;t use ls | grep. Use a glob or a for loop with a condition.<\/td>\n<\/tr>\n<tr>\n<td><code>expr 3 + 2<\/code><\/td>\n<td>Use $((..)), ${} or [[ ]] in place of antiquated expr.<\/td>\n<\/tr>\n<tr>\n<td><code>cat foo | grep bar<\/code><\/td>\n<td>Useless cat. Consider &#8216;cmd < file | ..' or 'cmd file | ..' instead.<\/td>\n<\/tr>\n<tr>\n<td><code>length=$(echo \"$var\" | wc -c\")<\/code><\/td>\n<td>See if you can use ${#variable} instead<\/td>\n<\/tr>\n<\/table>\n<p>&nbsp;<br \/> &nbsp; <br \/>\n<strong>ShellCheck recognizes common but wrong attempts at doing things<\/strong><\/p>\n<table>\n<tr>\n<th>Code<\/th>\n<th>ShellCheck tip<\/th>\n<\/tr>\n<tr>\n<td><code>var$n=42<\/code><\/td>\n<td>For indirection, use (associative) arrays or &#8216;read &#8220;var$n&#8221; <<< \"value\"'\".<br \/>(Bash says &#8220;var3=42: command not found&#8221;)<\/td>\n<\/tr>\n<tr>\n<td><code>${var$n}<\/code><\/li>\n<\/td>\n<td>To expand via indirection, use name=&#8221;foo$n&#8221;; echo &#8220;${!name}&#8221; <br \/>(Bash says &#8220;bad substitution&#8221;. )<\/td>\n<\/tr>\n<tr>\n<td><code>echo 'It\\'s time'<\/code><\/td>\n<td>Are you trying to escape that single quote? echo &#8216;You&#8217;\\&#8221;re doing it wrong&#8217;<br \/>(Bash says &#8220;unexpected end of file&#8221;)<\/td>\n<\/tr>\n<tr>\n<td><code>[ grep a b ]<\/code><\/td>\n<td>Use &#8216;if cmd; then ..&#8217; to check exit code, or &#8216;if [[ $(cmd) == .. ]]&#8217; to check output<br \/>(Bash says &#8220;[: a: binary operator expected&#8221;)<\/td>\n<\/tr>\n<tr>\n<td><code>var=grep a b<\/code><\/td>\n<td>To assign the output of a command, use var=$(cmd)<br \/>(Bash says &#8220;a: command not found&#8221;)<\/td>\n<\/tr>\n<\/table>\n<p>&nbsp;<br \/>\n<strong>ShellCheck can help with POSIX sh compliance and bashisms<\/strong><\/p>\n<p>When a script is declared with <code>#!\/bin\/sh<\/code>, ShellCheck checks for POSIX sh compliance, much like <code>checkbashisms<\/code>. <\/p>\n<p>&nbsp;<br \/>\n<strong>ShellCheck is free software, and can be used online and locally<\/strong><\/p>\n<p>ShellCheck is of course Free Software, and has a <a href=\"http:\/\/www.shellcheck.net\/about.html\">cute cli frontend<\/a> in addition to the <a href=\"http:\/\/www.shellcheck.net\">primary online version<\/a>. <\/p>\n<p>&nbsp;<br \/>\n<strong>ShellCheck wants your feedback and suggestions!<\/strong><br \/>\nDoes ShellCheck give you incorrect suggestions? Does it fail to parse your working code? Is there something it could have warned about, but didn&#8217;t? After pasting a script on <a href=\"http:\/\/www.shellcheck.net\">ShellCheck.net<\/a>, a tiny &#8220;submit feedback&#8221; link appears in the top right of the annotated script area. Click it to submit the code plus your comments, and I can take a look!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>tl;dr: ShellCheck is a bash\/sh static analysis and linting tool. Paste a shell command or script on ShellCheck.net and get feedback about many common issues, both in scripts that currently fail and scripts that appear to work just fine. There&#8217;s been a lot of progress since I first posted about it seven months ago. It &hellip; <a href=\"https:\/\/www.vidarholen.net\/contents\/blog\/?p=245\" class=\"more-link\">Continue reading<span class=\"screen-reader-text\"> &#8220;Paste shell script, get feedback: ShellCheck project update&#8221;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":"","jetpack_publicize_message":"","jetpack_is_tweetstorm":false,"jetpack_publicize_feature_enabled":true},"categories":[6,4],"tags":[11,21,46],"class_list":["post-245","post","type-post","status-publish","format-standard","hentry","category-basic-linux","category-linux","tag-bash","tag-shell-script","tag-shellcheck"],"jetpack_featured_media_url":"","_links":{"self":[{"href":"https:\/\/www.vidarholen.net\/contents\/blog\/index.php?rest_route=\/wp\/v2\/posts\/245","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.vidarholen.net\/contents\/blog\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.vidarholen.net\/contents\/blog\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.vidarholen.net\/contents\/blog\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.vidarholen.net\/contents\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=245"}],"version-history":[{"count":77,"href":"https:\/\/www.vidarholen.net\/contents\/blog\/index.php?rest_route=\/wp\/v2\/posts\/245\/revisions"}],"predecessor-version":[{"id":322,"href":"https:\/\/www.vidarholen.net\/contents\/blog\/index.php?rest_route=\/wp\/v2\/posts\/245\/revisions\/322"}],"wp:attachment":[{"href":"https:\/\/www.vidarholen.net\/contents\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=245"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.vidarholen.net\/contents\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=245"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.vidarholen.net\/contents\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=245"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}