### XML Output Example (CheckStyle) Source: https://github.com/koalaman/shellcheck/wiki/Integration Use the `checkstyle` format for XML output compatible with CheckStyle. Line and column numbers start at 1, assuming a tab size of 8. ```console $ shellcheck -f checkstyle myscript myotherscript ``` -------------------------------- ### Install ShellCheck using Cabal Source: https://github.com/koalaman/shellcheck/blob/master/README.md After cloning the ShellCheck repository and navigating to its directory, use this command to compile and install ShellCheck using Cabal. It will be installed in `~/.cabal/bin`. ```sh cabal install ``` -------------------------------- ### Handling process substitution failures with file descriptor duplication and wait Source: https://github.com/koalaman/shellcheck/wiki/SC2312 This example demonstrates how to handle process substitution failures by using file descriptor duplication with `exec` and `wait`. This allows retaining exit codes from processes started via process substitution. ```shell generate_data() { declare i for (( i = 0 ; i < 5 ; ++i )) do date -d "$RANDOM hours" done } consume_data() { declare line while IFS= read -r line do echo Consuming line: "$line" done } declare \ input_file_descriptor \ process # The following statement # # - uses process substitution to allow us to read the output of `generate_data` # via a filename and # - duplicates the file descriptor for that file so that it is not # immediately closed # # Note that process substitution uses either `pipe(2)` or named pipes (FIFOs) # with `O_RDONLY` or `O_WRONLY`, and so the file descriptor that is duplicated # via `[N]<&WORD` is only opened for reads exec {input_file_descriptor}< <( generate_data ) process=$! # Returns non-zero if `consume_data` does consume_data <&"$input_file_descriptor" # Returns non-zero if `generate_data` does wait "$process" ``` -------------------------------- ### Correct sudo redirect examples using tee Source: https://github.com/koalaman/shellcheck/wiki/SC2024 These examples show the correct way to use `sudo` with file writes and appends using the `tee` command. ```sh # Write to a file echo 3 | sudo tee /proc/sys/vm/drop_caches > /dev/null # Append to a file echo 'export FOO=bar' | sudo tee -a /etc/profile > /dev/null ``` -------------------------------- ### Modern shell arithmetic and string length Source: https://github.com/koalaman/shellcheck/wiki/SC2003 These examples demonstrate the correct and preferred way to perform arithmetic and get string length using modern shell features. ```sh i=$((1+2)) l=${#var} ``` -------------------------------- ### Correct sudo redirect example using cat Source: https://github.com/koalaman/shellcheck/wiki/SC2024 This example demonstrates the correct way to read from a file requiring elevated privileges using `sudo cat` piped to another command. ```sh # Read from a file sudo cat /etc/shadow | wc -l ``` -------------------------------- ### Download and Install Haskell Platform Source: https://github.com/koalaman/shellcheck/wiki/CentOS6 Downloads a specific version of the Haskell Platform and installs it. This process involves creating a temporary directory, downloading the tarball, extracting it, running the installation script, and cleaning up the temporary directory. ```sh dir="$(mktemp -d)" pushd "$dir" wget https://haskell.org/platform/download/7.10.2/haskell-platform-7.10.2-a-unknown-linux-deb7.tar.gz tar xvzf haskell-platform-7.10.2-a-unknown-linux-deb7.tar.gz ./install-haskell-platform.sh popd rm -r "$dir" ``` -------------------------------- ### Install ShellCheck binary on Linux Source: https://github.com/koalaman/shellcheck/blob/master/README.md This script downloads, decompresses, and installs a pre-compiled ShellCheck binary on Linux systems. Ensure 'xz' is installed for decompression. Replace 'stable' with a specific version or 'latest' if needed. ```bash scversion="stable" # or "v0.4.7", or "latest" wget -qO- "https://github.com/koalaman/shellcheck/releases/download/${scversion?}/shellcheck-${scversion?}.linux.x86_64.tar.xz" | tar -xJv cp "shellcheck-${scversion}/shellcheck" /usr/bin/ shellcheck --version ``` -------------------------------- ### Install ShellCheck with Nix Source: https://github.com/koalaman/shellcheck/blob/master/README.md Use this command to install ShellCheck using the Nix package manager. ```sh nix-env -iA nixpkgs.shellcheck ``` -------------------------------- ### Parameter Expansion: Matching Undesired Parts (POSIX sh) Source: https://github.com/koalaman/shellcheck/wiki/SC3057 This example uses parameter expansion to extract a number from the beginning of a string and the remaining text. It relies on the fact that digits are at the start of the string. ```sh #!/usr/bin/env sh exitForReasonY='6Stopping because of 8x Y.' yNumber="${exitForReasonY%%[![:digit:]]*}" yText="${exitForReasonY#${exitForReasonY%%[![:digit:]]*}}" # or : yText="${exitForReasonY#${yNumber?}}" printf "The ''reason y'' has number '%s' and its message is: '%s'.\n" "${yNumber?}" "${yText?}" ``` -------------------------------- ### Correct Shell Loop Syntax with 'do' Source: https://github.com/koalaman/shellcheck/wiki/SC1063 These examples show the correct ways to use 'do' in a shell loop. Either place 'do' at the start of a new line or use a semicolon before it. ```sh for file in *; do echo "$file" done ``` ```sh for file in * do echo "$file" done ``` -------------------------------- ### Install ShellCheck using Winget on Windows Source: https://github.com/koalaman/shellcheck/blob/master/README.md Install ShellCheck on Windows using the Windows Package Manager (winget). This command installs the ShellCheck package from the official repository. ```cmd C:\> winget install --id koalaman.shellcheck ``` -------------------------------- ### JSON Output Example Source: https://github.com/koalaman/shellcheck/wiki/Integration Use the `json1` format for a structured JSON output. Line and column numbers start at 1, and tabs count as 1 character. This format includes fix suggestions. ```console $ shellcheck -f json1 myscript myotherscript { "comments": [ { "file": "myotherscript", "line": 2, "endLine": 2, "column": 1, "endColumn": 2, "level": "error", "code": 1035, "message": "You need a space after the [ and before the ].", "fix": null }, { "file": "myscript", "line": 2, "endLine": 2, "column": 6, "endColumn": 8, "level": "warning", "code": 2039, "message": "In POSIX sh, echo flags are undefined.", "fix": null }, { "file": "myscript", "line": 2, "endLine": 2, "column": 9, "endColumn": 11, "level": "info", "code": 2086, "message": "Double quote to prevent globbing and word splitting.", "fix": { "replacements": [ { "line": 2, "endLine": 2, "precedence": 7, "insertionPoint": "afterEnd", "column": 9, "replacement": "\"", "endColumn": 9 }, { "line": 2, "endLine": 2, "precedence": 7, "insertionPoint": "beforeStart", "column": 11, "replacement": "\"", "endColumn": 11 } ] } } ] } ``` -------------------------------- ### Install Development Tools and GMP Source: https://github.com/koalaman/shellcheck/wiki/CentOS6 Installs essential development tools and the GMP library. A symbolic link is created for compatibility with older Haskell Platform versions. ```sh yum groupinstall "Development Tools" -y yum install gmp-devel # may need epel sudo ln -s /usr/lib64/libgmp.so.3 /usr/lib64/libgmp.so.10 ``` -------------------------------- ### Install ShellCheck with Flox Source: https://github.com/koalaman/shellcheck/blob/master/README.md Use this command to install ShellCheck using the Flox package manager. ```sh flox install shellcheck ``` -------------------------------- ### Install ShellCheck using Cabal Source: https://github.com/koalaman/shellcheck/wiki/CentOS6 Updates the Cabal package index and installs the ShellCheck package. Ensure the Haskell Platform is installed and configured correctly before running this. ```sh cabal update cabal install shellcheck ``` -------------------------------- ### Install ShellCheck using Chocolatey on Windows Source: https://github.com/koalaman/shellcheck/blob/master/README.md Use the Chocolatey package manager to install ShellCheck on Windows. This command installs the latest stable version. ```cmd C:\> choco install shellcheck ``` -------------------------------- ### GCC-style Error Messages Example Source: https://github.com/koalaman/shellcheck/wiki/Integration Use the `gcc` format for output compatible with GCC-style error parsers. Line and column numbers start at 1, assuming a tab size of 1. ```console $ shellcheck -f gcc myscript myotherscript myscript:2:6: warning: In POSIX sh, echo flags are undefined. [SC2039] myscript:2:9: note: Double quote to prevent globbing and word splitting. [SC2086] myotherscript:2:2: error: You need a space after the [ and before the ]. [SC1035] ``` -------------------------------- ### Install Specific ShellCheck Version Source: https://github.com/koalaman/shellcheck/wiki/GitHub-Actions Pin to a specific ShellCheck version by downloading and installing it directly. This ensures reproducible builds. ```yaml - name: Install specific ShellCheck version run: | wget https://github.com/koalaman/shellcheck/releases/download/v0.9.0/shellcheck-v0.9.0.linux.x86_64.tar.xz tar -xf shellcheck-v0.9.0.linux.x86_64.tar.xz sudo cp shellcheck-v0.9.0/shellcheck /usr/bin/ ``` -------------------------------- ### Demonstrating Problematic Execution Source: https://github.com/koalaman/shellcheck/wiki/SC2084 This example shows the shell's behavior when it attempts to execute the output of an arithmetic expansion as a command, resulting in a 'command not found' error. ```sh $ i=4 $ $(( i++ )) 4: command not found $ echo $i 5 ``` -------------------------------- ### Alternative methods for writing to files with sudo Source: https://github.com/koalaman/shellcheck/wiki/SC2024 These examples show alternative commands like `dd` and `sed` that can be used with `sudo` to write data to files. ```sh echo 'data' | sudo dd of=file ``` ```sh echo 'data' | sudo sed 'w file' ``` -------------------------------- ### Manually Install Shellcheck on Linux Source: https://github.com/koalaman/shellcheck/wiki/CircleCI Install Shellcheck using apt-get in a Linux-based CircleCI job. This method is suitable for Debian/Ubuntu environments. ```yaml version: 2.1 jobs: build: machine: true steps: - checkout - run: apt-get install shellcheck ``` -------------------------------- ### Example of ls output with special characters Source: https://github.com/koalaman/shellcheck/wiki/SC2012 This example demonstrates how `ls` can display filenames with special characters, which can be problematic for parsing. ```console $ ls -l total 0 -rw-r----- 1 me me 0 Feb 5 20:11 foo?bar -rw-r----- 1 me me 0 Feb 5 2011 foo?bar -rw-r----- 1 me me 0 Feb 5 20:11 foo?bar ``` -------------------------------- ### Install ShellCheck on CentOS 6 / RHEL 6 Source: https://github.com/koalaman/shellcheck/wiki/More-Installation-Guides Installs Haskell dependencies, Haskell Platform, and ShellCheck using cabal. Requires root privileges for some commands. ```bash # Haskell Deps. Or read on and use that source in the wiki. yum -y groupinstall "Development Tools" yum -y install gmp-devel zlib # may need epel; zlib as shellcheck builddep reported in #519 sudo ln -s libgmp.so.3 /usr/lib64/libgmp.so.10 # HACK # Get haskell. https://www.haskel.org/platform/linux.html#linux-generic # Or follow https://wiki.haskell.org/GNU/Linux#RHEL.2C_CentOS.2C_Scientific_Linux_5_and_6_and_Fedora_16_and_17. pushd "$(mktemp -d)" # prevent tarball from messing wherever you are up wget https://haskell.org/platform/download/7.10.2/haskell-platform-7.10.2-a-unknown-linux-deb7.tar.gz tar xvzf haskell-platform-7.10.2-a-unknown-linux-deb7.tar.gz ./install-haskell-platform.sh popd # do the normal cabal thing cabal update cabal install shellcheck cp ~/.cabal/bin/shellcheck /usr/local/bin ``` -------------------------------- ### Install ShellCheck using Scoop on Windows Source: https://github.com/koalaman/shellcheck/blob/master/README.md Install ShellCheck on Windows using the Scoop package manager. This command adds ShellCheck to your system's available commands. ```cmd C:\> scoop install shellcheck ``` -------------------------------- ### Problematic sudo redirect examples Source: https://github.com/koalaman/shellcheck/wiki/SC2024 These examples demonstrate incorrect usage of `sudo` with shell redirects, which can lead to permission errors. ```sh # Write to a file sudo echo 3 > /proc/sys/vm/drop_caches # Append to a file sudo echo 'export FOO=bar' >> /etc/profile # Read from a file sudo wc -l < /etc/shadow ``` -------------------------------- ### Get ShellCheck Help Information Source: https://github.com/koalaman/shellcheck/wiki/Directive Commands to display the manual page or help information for ShellCheck, listing supported options. ```console man shellcheck ``` ```console shellcheck --help ``` -------------------------------- ### Correcting Command Substitution Redirection in Shell Source: https://github.com/koalaman/shellcheck/wiki/SC2328 These examples show how to correctly capture command output, write it to a file, or both, when using command substitutions. ```sh var=$(tr -d ':' < input.txt) ``` ```sh var=$(tr -d ':' < input.txt | tee output.txt) ``` ```sh tr -d ':' < input.txt > output.txt ``` -------------------------------- ### Verify ShellCheck installation path Source: https://github.com/koalaman/shellcheck/blob/master/README.md After updating your PATH, run this command to verify that the system can locate the ShellCheck executable and display its path. ```sh which shellcheck ``` -------------------------------- ### Insecure `eval` in Loop Example Source: https://github.com/koalaman/shellcheck/wiki/SC2089 Shows an example of insecure `eval` usage within a loop, highlighting potential security vulnerabilities like command injection. ```bash for f in *.txt; do args="-lh '$1'" # Example security exploit eval ls "$args" # Do not copy and use done ``` -------------------------------- ### List Optional Checks Source: https://github.com/koalaman/shellcheck/wiki/Directive Command to list all optional checks supported by ShellCheck, along with examples. ```console shellcheck --list-optional ``` -------------------------------- ### Manually Install Shellcheck on macOS Source: https://github.com/koalaman/shellcheck/wiki/CircleCI Install Shellcheck using Homebrew in a macOS CircleCI job. Ensure Homebrew is available in your environment. ```yaml version: 2.1 jobs: build: macos: xcode: "9.0" steps: - checkout - run: brew install shellcheck ``` -------------------------------- ### Find command exception for excluding specific files Source: https://github.com/koalaman/shellcheck/wiki/SC2146 This example demonstrates how to use grouping to decompress all `.gz` files except for `.tar.gz` files. ```sh find . -name '*.tar.gz' -o \( -name '*.gz' -exec gzip -d {} + \) ``` -------------------------------- ### Unified Diff Output Example Source: https://github.com/koalaman/shellcheck/wiki/Integration Use the `-f diff` option to generate standard unified diff output, which is useful for displaying suggested fixes. ```console $ shellcheck -f diff file --- a/file +++ b/file @@ -1,2 +1,2 @@ #!/bin/sh -echo $1 +echo "$1" ``` -------------------------------- ### ShellCheck RC File Configuration Source: https://github.com/koalaman/shellcheck/blob/master/shellcheck.1.md Example of a .shellcheckrc file demonstrating various configuration options for source paths, external sources, and enabling/disabling specific checks. ```shell # Look for 'source'd files relative to the checked script, # and also look for absolute paths in /mnt/chroot source-path=SCRIPTDIR source-path=/mnt/chroot # Since 0.9.0, values can be quoted with '' or "" to allow spaces source-path="My Documents/scripts" # Allow opening any 'source'd file, even if not specified as input external-sources=true # Turn on warnings for unquoted variables with safe values enable=quote-safe-variables # Turn on warnings for unassigned uppercase variables enable=check-unassigned-uppercase # Allow [ ! -z foo ] instead of suggesting -n disable=SC2236 ``` -------------------------------- ### SSH Here Document with Command Substitution Source: https://github.com/koalaman/shellcheck/wiki/SC2087 This problematic example illustrates how client-side expansion of command substitutions within a here document can lead to unexpected empty results on the server. ```sh ssh host << EOF x="$(uname -a)" echo "$x" EOF ``` -------------------------------- ### ShellCheck Console Output Example Source: https://github.com/koalaman/shellcheck/wiki/heading This is an example of the output you might see when running ShellCheck on a script. It indicates a specific warning (SC1118) related to whitespace after a here-doc end token on line 5 of 'myscript'. ```console $ shellcheck myscript In myscript line 5: eof ^-- SC1118: Delete whitespace after the here-doc end token. ``` -------------------------------- ### Alternative methods for appending to files with sudo Source: https://github.com/koalaman/shellcheck/wiki/SC2024 These examples demonstrate alternative commands like `awk` and `sh -c` for appending data to files using `sudo`. ```sh echo 'data' | sudo awk '{ print $0 >> "file" }' ``` ```sh echo 'data' | sudo sh -c 'cat >> file' ``` -------------------------------- ### Quoting within Subshells Source: https://github.com/koalaman/shellcheck/wiki/SC2086 Variables within subshells started by `$( )` must be quoted independently. This example shows a variable quoted within the subshell. ```sh echo "This $variable is quoted $(but this $variable is not)" ``` ```sh echo "This $variable is quoted $(and now this "$variable" is too)" ``` -------------------------------- ### Correct Regex for Start of Word Source: https://github.com/koalaman/shellcheck/wiki/SC2022 This snippet demonstrates the correct way to use a regular expression with grep to match words starting with 'foo'. The '^' anchor ensures the pattern matches only at the beginning of a line or word. ```sh grep '^foo' ``` -------------------------------- ### Example of sh -c Usage for Path Manipulation Source: https://github.com/koalaman/shellcheck/wiki/SC2014 This example demonstrates how sh -c can be used to process a filename argument, showing how $1 and $(dirname "$1") work within an inlined shell script. ```sh $ sh -c 'echo "$1 is in $(dirname "$1")"' _ "mydir/myfile" ``` -------------------------------- ### Corrected mkdir and chmod usage Source: https://github.com/koalaman/shellcheck/wiki/SC2174 This code shows the correct way to create directories with specific permissions by separating the creation and permission setting steps. ```sh mkdir -p foo/bar/baz chmod 0755 foo/bar/baz foo/bar foo ``` -------------------------------- ### Demonstrate printf argument ignoring Source: https://github.com/koalaman/shellcheck/wiki/SC2182 This example shows how printf ignores extra arguments when the format string lacks corresponding placeholders. ```sh printf hello world\n ``` -------------------------------- ### Correct code using command -v and hash Source: https://github.com/koalaman/shellcheck/wiki/SC2230 These examples show the correct way to find the path of an external command or check for its existence using the POSIX builtins `command -v` and `hash`. ```shell # For the path of a single, unaliased, external command, # or to check whether this will just "run" in this shell: command -v grep ``` ```shell # To check whether commands exist, without obtaining a reusable path: hash grep ``` -------------------------------- ### Correct SSH Here Document Expansion Source: https://github.com/koalaman/shellcheck/wiki/SC2087 This example demonstrates the correct way to quote the EOF token in an SSH here document to ensure server-side expansion of variables. ```sh ssh host.example.com << "EOF" echo "Logged in on $HOSTNAME" EOF ``` -------------------------------- ### Bash parameter expansion table for string replacement Source: https://github.com/koalaman/shellcheck/wiki/SC2001 Illustrates various string replacement scenarios using Bash parameter expansion and their corresponding sed equivalents, showing the resulting output for different patterns. ```bash var="foo foo" # the following two echo's should be equivalent: echo "$var" | sed 's/^foo/bar/g' echo ${var/#foo/bar} ``` ```bash var="foo foo" # the following two echo's should be equivalent: echo "$var" | sed 's/^foo/bar/g' echo ${var/#foo/bar} ``` ```bash var="foo foo" # the following two echo's should be equivalent: echo "$var" | sed 's/^foo/bar/g' echo ${var/#foo/bar} ``` ```bash var="foo foo" # the following two echo's should be equivalent: echo "$var" | sed 's/^foo/bar/g' echo ${var/#foo/bar} ``` ```bash var="foo foo" # the following two echo's should be equivalent: echo "$var" | sed 's/^foo/bar/g' echo ${var/#foo/bar} ``` ```bash var="foo foo" # the following two echo's should be equivalent: echo "$var" | sed 's/^foo/bar/g' echo ${var/#foo/bar} ``` -------------------------------- ### Capturing Function Output Source: https://github.com/koalaman/shellcheck/wiki/SC2152 This example demonstrates how to capture the standard output of a shell function into a variable. This is the recommended method for retrieving string or non-integer results from functions. ```sh message=$(myfunc) echo "The function wrote: $message" ``` -------------------------------- ### Bash brace expansion for multiple file extensions Source: https://github.com/koalaman/shellcheck/wiki/SC2102 This example shows how to use Bash's brace expansion `{}` to match multiple file extensions, which is a more readable alternative to multiple globs. ```sh cat *.{dev,prod,test}.conf ``` -------------------------------- ### Problematic find -exec with Command Substitution Source: https://github.com/koalaman/shellcheck/wiki/SC2014 Avoid using command substitutions directly in find -exec if they are intended to be evaluated per file. This example demonstrates the incorrect approach where $(dirname {}) is evaluated only once before find starts. ```sh find . -name '*.tar' -exec tar xf {} -C "$(dirname {})" \; ``` -------------------------------- ### Setting ShellCheck Options via Environment Variable Source: https://github.com/koalaman/shellcheck/blob/master/shellcheck.1.md Example of setting the SHELLCHECK_OPTS environment variable to provide default flags for ShellCheck invocations. ```shell export SHELLCHECK_OPTS='--shell=bash --exclude=SC2016' ``` -------------------------------- ### Exception: Intentional Word Splitting with pkg-config Source: https://github.com/koalaman/shellcheck/wiki/SC2046 This example shows a rare case where intentional word splitting is desired for command-line arguments generated by `pkg-config`. ```sh # shellcheck disable=SC2046 gcc $(pkg-config --libs openssl) client.c ``` -------------------------------- ### Handle non-POSIX environments or unsupported pgrep filters Source: https://github.com/koalaman/shellcheck/wiki/SC2009 This example shows how to bypass the `pgrep` recommendation if targeting POSIX userlands or if `pgrep` lacks support for specific filtering criteria, such as 'nice' values. ```sh # pgrep does not support filtering by 'nice' value # shellcheck disable=SC2009 ps -axo nice=,pid= | grep -v '^ 0' ``` -------------------------------- ### Code Walkthrough: Parameter Expansion Simple Pattern (POSIX sh) Source: https://github.com/koalaman/shellcheck/wiki/SC3057 This section provides a detailed explanation of the parameter expansion steps used to manipulate the 'part' string. It clarifies how prefixes and suffixes are removed. ```sh #!/usr/bin/env sh part="zyxwvutsrqponmlkjihgfedcba" #echo "${part:5:3}" part="${part%${part#????????}}" ## Removed smallest prefix from text where prefix matches pattern ???????? ## in this case : "rqponmlkjihgfedcba" ## "${part%${part#????????}}" = "${part%"rqponmlkjihgfedcba"}" = "zyxwvuts" ## Removed smallest suffix from part of text where suffix matches pattern ${part#????????} (i.e. "rqponmlkjihgfedcba") part="${part#?????}" ## Removed smallest prefix from text where prefix matches ????? (i.e. "zyxwv") printf '%s\n' "${part?}" ``` -------------------------------- ### Avoid variable names starting with numbers Source: https://github.com/koalaman/shellcheck/wiki/SC2282 Variable names in shell scripting must start with a letter or an underscore. Assigning to a variable that starts with a digit will be interpreted as a command. Use a valid variable name. ```sh 411toppm=true ``` ```sh _411toppm=true ``` -------------------------------- ### Parameter Expansion: Simple Pattern (POSIX sh) Source: https://github.com/koalaman/shellcheck/wiki/SC3057 This example demonstrates removing a prefix and suffix from a string using parameter expansion. It first removes a prefix of a specific length, then a suffix of a specific length. ```sh #!/usr/bin/env sh part="zyxwvutsrqponmlkjihgfedcba" #echo "${part:5:3}" part="${part%${part#????????}}" part="${part#?????}" printf '%s\n' "${part?}" ``` -------------------------------- ### Bash parameter expansion vs. sed for string replacement Source: https://github.com/koalaman/shellcheck/wiki/SC2001 Demonstrates equivalent string replacement using both sed and Bash parameter expansion. The parameter expansion variants offer different matching behaviors (e.g., start of string, end of string, global). ```bash var="foo foo" # the following two echo's should be equivalent: echo "$var" | sed 's/^foo/bar/g' echo ${var/#foo/bar} ``` ```bash var="foo foo" # the following two echo's should be equivalent: echo "$var" | sed 's/^foo/bar/g' echo ${var/#foo/bar} ``` -------------------------------- ### Performance Comparison: Subshell vs. Direct Test Source: https://github.com/koalaman/shellcheck/wiki/SC2234 Demonstrates the significant performance difference between using a subshell for a test command and executing it directly. The subshell approach is orders of magnitude slower. ```console i=0; time while ( [ "$i" -lt 10000 ] ); do i=$((i+1)); done real 0m6.998s user 0m3.453s sys 0m3.464s ``` ```console i=0; time while [ "$i" -lt 10000 ]; do i=$((i+1)); done real 0m0.055s user 0m0.054s sys 0m0.001s ``` -------------------------------- ### Building Command Lines with Arrays Source: https://github.com/koalaman/shellcheck/wiki/SC2086 When building command lines that require splitting on spaces, use arrays (Bash, Ksh, Zsh) instead of simple strings. This example demonstrates adding an option to an array and then using it with `make`. ```sh options="-j 5 -B" [[ $debug == "yes" ]] && options="$options -d" make $options file ``` ```sh options=(-j 5 -B) # ksh88: set -A options -- -j 5 -B [[ $debug == "yes" ]] && options=("${options[@]}" -d) make "${options[@]}" file ``` -------------------------------- ### Backgrounding a Command with '&' Source: https://github.com/koalaman/shellcheck/wiki/SC1132 This example illustrates how to correctly background a command using '&' by adding a space or linefeed after it. This clarifies intent to both the shell and tools like ShellCheck, preventing misinterpretation. ```sh sleep 10& wait ``` -------------------------------- ### Python Example: Literal Strings vs. Code Source: https://github.com/koalaman/shellcheck/wiki/SC2089 Illustrates how Python treats literal strings differently from executable code, similar to how shells handle quoted arguments. ```python #!/usr/bin/env python3 print 1+1 # prints 2 a="1+1" print a # prints 1+1, not 2 ``` -------------------------------- ### Correct Command Expansion in Shell Source: https://github.com/koalaman/shellcheck/wiki/SC1077 Demonstrates the preferred method for command expansion using $(command) and the deprecated method using backticks (`command`). The latter may trigger SC2006 warnings. ```sh echo "Your username is $(whoami)" # Preferred ``` ```sh echo "Your username is `whoami`" # Deprecated, will give [SC2006] ``` -------------------------------- ### ShellCheck Error Message Example Source: https://github.com/koalaman/shellcheck/wiki/SC1041 This example illustrates the output from ShellCheck when encountering SC1041 and SC1042 errors, highlighting the problematic line and close matches. ```sh In foo line 4: Hello ^-- SC1041: Found 'eof' further down, but not on a separate line. ^-- SC1042: Close matches include '-eof' (!= 'eof'). ``` -------------------------------- ### Correct sudo cd command using sh -c Source: https://github.com/koalaman/shellcheck/wiki/SC2232 Shows the correct way to change directory to `/root` and print the working directory with `sudo` by executing a new shell with `sudo sh -c`. ```sh sudo sh -c 'cd /root && pwd' ``` -------------------------------- ### Docker Wrapper Script for ShellCheck Source: https://github.com/koalaman/shellcheck/wiki/Contrib A bash script to run ShellCheck via Docker without local installation. It works across different operating systems with Docker installed. ```bash #!/bin/bash - for last; do true; done docker run --rm -iv "$( cd "$( dirname -- "${last}" )" && pwd )":/mnt koalaman/shellcheck "${@:1:$(($#-1))}" "$(basename -- "${last}")" ``` -------------------------------- ### ShellCheck SC2148: Problematic code starting with '===' Source: https://github.com/koalaman/shellcheck/wiki/SC2274 This code snippet demonstrates a line that ShellCheck flags as problematic because it starts with '===' and is interpreted as a command. It was likely intended as a comment. ```sh ===================== MAIN SECTION ======================= ``` -------------------------------- ### Identical HTML output with and without inner quotes Source: https://github.com/koalaman/shellcheck/wiki/SC2140 These examples illustrate that the inner quotes in the problematic HTML example are redundant and do not affect the output. The corrected version avoids this redundancy. ```sh echo "" > file.html echo "" > file.html ``` -------------------------------- ### Alternative `cd` failure handling Source: https://github.com/koalaman/shellcheck/wiki/SC2164 Demonstrates alternative methods for handling `cd` failures, including custom error messages and conditional execution within subshells or command substitutions. ```sh cd foo || { echo "Failure"; exit 1; } ``` ```sh cd foo || ! echo "Failure" ``` ```sh if cd foo; then echo "Ok"; else echo "Fail"; fi ``` ```sh <(cd foo && cmd) ``` ```sh <(cd foo || exit; cmd) ``` -------------------------------- ### Correct printf usage with placeholder Source: https://github.com/koalaman/shellcheck/wiki/SC2182 This demonstrates the correct way to use printf with a format specifier to include a variable. ```sh printf "hello %s\n" "world" ``` -------------------------------- ### Copy ShellCheck to Global Bin Directory Source: https://github.com/koalaman/shellcheck/wiki/CentOS6 Copies the installed ShellCheck executable to a global binary directory, making it accessible system-wide. This is useful for deploying on other systems without a full Haskell installation. ```sh cp ~/.cabal/bin/shellcheck /usr/local/bin # portable to other el6 systems without Haskell ``` -------------------------------- ### Command substitution vs direct execution Source: https://github.com/koalaman/shellcheck/wiki/SC2091 Illustrates the difference between capturing output with command substitution and directly executing a command. Direct execution is preferred unless the output is intended to be a command. ```sh sayhello() { echo "hello world"; } $(sayhello) ``` ```sh sayhello() { echo "hello world"; } sayhello ``` -------------------------------- ### Shell Script Exit Code Exception Example Source: https://github.com/koalaman/shellcheck/wiki/SC2320 This example shows an exception where `$?` might be intentionally used after an `echo` command if the intent is to capture the exit status of the `echo` itself, for instance, when writing to a file. ```sh if echo $$ > "$pidfile"; then status=0; else status=1; fi ``` -------------------------------- ### ShellCheck SC2155: Variable Misspelling Example Source: https://github.com/koalaman/shellcheck/wiki/SC2153 This example demonstrates the problematic code where a variable MYVARIABLE is echoed, but MY_VARIABLE is assigned. ShellCheck flags this as a potential misspelling. Use directives to disable this check if intentional. ```sh MY_VARIABLE="hello world" echo "$MYVARIABLE" ``` ```sh MY_VARIABLE="hello world" echo "$MY_VARIABLE" ``` -------------------------------- ### printf Format String Interpretation Example (Shell) Source: https://github.com/koalaman/shellcheck/wiki/SC2059 This example demonstrates how including a variable in the printf format string can lead to errors when the variable contains characters that printf interprets as format specifiers or escape sequences. ```sh coverage='96%' printf "Unit test coverage: %s\n" "$coverage" printf "Unit test coverage: $coverage\n" ``` -------------------------------- ### Get file size using wc -c Source: https://github.com/koalaman/shellcheck/wiki/SC2012 Use `wc -c` to get the file size in bytes. This is a portable method, though potentially slower than `stat`. The result may require trimming whitespace. ```sh $(( $(wc -c < "filename") )) ``` -------------------------------- ### Common Beginner Shell Scripting Mistakes Source: https://github.com/koalaman/shellcheck/blob/master/README.md Covers typical syntax errors made by beginners, including incorrect assignments, indirect references, array initialization, and misuse of command substitution. Focus on correct syntax for variables, arrays, and control flow. ```sh var = 42 # Spaces around = in assignments ``` ```sh $foo=42 # $ in assignments ``` ```sh for $var in *; do ... # $ in for loop variables ``` ```sh var$n="Hello" # Wrong indirect assignment ``` ```sh echo ${var$n} # Wrong indirect reference ``` ```sh var=(1, 2, 3) # Comma separated arrays ``` ```sh array=( [index] = value ) # Incorrect index initialization ``` ```sh echo $var[14] # Missing {} in array references ``` ```sh echo "Argument 10 is $10" # Positional parameter misreference ``` ```sh if $(myfunction); then ..; fi # Wrapping commands in $() ``` ```sh else if othercondition; then .. # Using 'else if' ``` ```sh f; f() { echo "hello world; } # Using function before definition ``` ```sh [ false ] # 'false' being true ``` ```sh if ( -f file ) # Using (..) instead of test ``` -------------------------------- ### POSIX sh multiple globs for file extensions Source: https://github.com/koalaman/shellcheck/wiki/SC2102 In POSIX compliant shells, brace expansion and extglob are not available. This example shows how to match multiple file extensions by listing each glob pattern separately. ```sh cat *.dev.conf *.prod.conf *.test.conf ``` -------------------------------- ### Incorrect Glob as Regex Source: https://github.com/koalaman/shellcheck/wiki/SC2022 This snippet shows a common mistake where a glob pattern 'foo*' is used with grep, intending to match words starting with 'foo'. However, as a regex, 'foo*' matches 'f' followed by one or more 'o's, not necessarily at the start of the word. ```sh grep 'foo*' ``` -------------------------------- ### Correct Shebang Syntax Source: https://github.com/koalaman/shellcheck/wiki/SC1084 The shebang line must start with `#!` followed by the interpreter path. ```sh #!/bin/sh echo "Hello World" ``` -------------------------------- ### Clone ShellCheck Linter Repository Source: https://github.com/koalaman/shellcheck/wiki/Phabricator Clone the ShellCheck linter repository into the extensions directory of your Arcanist installation. ```bash cd /path/to/arcanist cd .. git clone https://github.com/dereckson/shellcheck-linter.git ``` -------------------------------- ### Creating Files with Special Characters for Testing Source: https://github.com/koalaman/shellcheck/wiki/SC2045 These commands create sample files with spaces, globs, and other special characters to demonstrate the fragility of parsing `ls` output. ```sh touch 'filename with spaces.wav' touch 'filename with * globs.wav' touch 'More_Globs[2003].wav' touch 'files_with_fønny_chæracters_in_certain_locales.wav' ``` -------------------------------- ### Correct <<- Indentation with Tabs Source: https://github.com/koalaman/shellcheck/wiki/SC1040 When using <<- here-documents, indent the content with tabs. The end token should align with the start of the command. ```sh ^Icat <<- foo ^I^IHello world ^Ifoo ``` -------------------------------- ### Correct ln command with source and destination Source: https://github.com/koalaman/shellcheck/wiki/SC2226 When creating a link, always specify both the source file and the destination. This ensures the command behaves as expected. ```sh ln "$file" "$dir" ``` ```sh ln /foo/bar/baz . ``` -------------------------------- ### Problematic expr usage Source: https://github.com/koalaman/shellcheck/wiki/SC2003 These examples show the problematic usage of the `expr` command for arithmetic and string length operations. ```sh i=$(expr 1 + 2) l=$(expr length "$var") ``` -------------------------------- ### Problematic Source Command Source: https://github.com/koalaman/shellcheck/wiki/SC1091 This is an example of a source command that might trigger the SC1091 error if ShellCheck cannot access 'somefile'. ```sh source somefile ``` -------------------------------- ### ShellCheck with Find Command Source: https://github.com/koalaman/shellcheck/wiki/Azure-Pipelines This command demonstrates the recommended approach to run ShellCheck on multiple scripts by using `find` to locate the files and pass them as arguments. ```bash shellcheck $(find $(pwd)/myscripts/ -name "*.sh") ``` -------------------------------- ### Problematic code for deleting files with dashes Source: https://github.com/koalaman/shellcheck/wiki/SC2035 This code will fail to delete files starting with a dash, as they will be interpreted as command-line options. ```shell rm * ``` -------------------------------- ### Correct Bash Name Matching Prefix Usage Source: https://github.com/koalaman/shellcheck/wiki/SC3056 This code demonstrates the correct usage of name matching prefixes `${!ANDROID_*}`, which is supported in bash. Switch to bash to use this feature. ```bash #!/bin/bash echo "${!ANDROID_*}" ``` -------------------------------- ### Incorrect Shebang Line in Shell Scripts Source: https://github.com/koalaman/shellcheck/wiki/SC1104 Avoid using only `!` for the shebang line, as it must start with `#!` to correctly specify the interpreter. ```sh !/bin/sh echo "Hello" ``` -------------------------------- ### Bash extglob for multiple file extensions Source: https://github.com/koalaman/shellcheck/wiki/SC2102 This example uses Bash's extended globbing `extglob` with `shopt -s extglob` to match multiple file extensions. The `@()` syntax specifies alternatives. ```sh shopt -s extglob cat *.@(dev|prod|test).conf ``` -------------------------------- ### Handle pipefail in POSIX sh Source: https://github.com/koalaman/shellcheck/wiki/SC3040 Demonstrates how to emulate 'set -o pipefail' in POSIX sh by checking exit codes of pipeline commands. This approach is useful when 'pipefail' is not natively supported. ```sh #!/bin/sh set -o pipefail if cmd1 | cmd2 | cmd3 then echo "Success" fi ``` ```sh fail="$(mktemp)" if { cmd1 || echo > "$fail"; } | { cmd2 || echo > "$fail"; } | cmd3 && [ ! -s "$fail" ] then echo "Success" fi rm "$fail" ``` -------------------------------- ### ShellCheck Optional Check: avoid-negated-conditions Source: https://github.com/koalaman/shellcheck/wiki/Optional Suggests removing unnecessary comparison negations. The 'fix' example demonstrates a more direct comparison. ```sh name: avoid-negated-conditions desc: Suggest removing unnecessary comparison negations example: [ ! "$var" -eq 1 ] fix: [ "$var" -ne 1 ] ``` -------------------------------- ### Caveat: command -v does not check ALL parameters Source: https://github.com/koalaman/shellcheck/wiki/SC2230 Demonstrates that `command -v` exits with 0 even if not all specified commands exist, unlike `which`. ```shell # grep is in /usr/bin/grep # foobar is not in path # $ command -v -- grep foobar; echo $? 0 ``` -------------------------------- ### Define Shell Function Before Calling Source: https://github.com/koalaman/shellcheck/wiki/SC2218 Shell functions must be defined before they are invoked. This example shows the correct order of definition and call. ```sh #!/bin/sh myfunction myfunction() { echo "Hello World" } ``` ```sh #!/bin/sh myfunction() { echo "Hello World" } myfunction ``` -------------------------------- ### Problematic script with carriage returns Source: https://github.com/koalaman/shellcheck/wiki/SC1017 This example shows a script with Windows-style line endings, where carriage return characters (^M) are present. ```console $ cat -v myscript #!/bin/sh^M echo "Hello World"^M ``` -------------------------------- ### Correct associative array initialization Source: https://github.com/koalaman/shellcheck/wiki/SC2190 Associative arrays must have an index specified for each element. This example demonstrates correct initialization with an index. ```sh declare -A foo foo=( [key]=myvalue ) ``` -------------------------------- ### Incorrect associative array initialization Source: https://github.com/koalaman/shellcheck/wiki/SC2190 Associative arrays require an index for each element. This example shows incorrect initialization without an index. ```sh declare -A foo foo=( myvalue ) ``` -------------------------------- ### Run ShellCheck with Custom Check via Quickrun Source: https://github.com/koalaman/shellcheck/wiki/DevGuide Execute ShellCheck using the `quickrun` script, which provides a quick way to test analysis on piped input, applying the custom check. ```sh ./quickrun - <<< "sort file > tmp" ``` -------------------------------- ### Avoid Decimal Comparisons in Bash Source: https://github.com/koalaman/shellcheck/wiki/SC2072 Bash arithmetic comparisons do not support decimal numbers. This example shows a problematic comparison with a decimal. ```sh [[ 2 -lt 3.14 ]] ``` -------------------------------- ### Checking for directory existence with globs Source: https://github.com/koalaman/shellcheck/wiki/SC2144 This example demonstrates how to check if files matching a glob pattern exist, specifically for directory existence. It uses a for loop and breaks after the first iteration. ```sh for f in /path/to/your/files* do ## Check if the glob gets expanded to existing files. ## If not, f here will be exactly the pattern above ## and the exists test will evaluate to false. [ -e "$f" ] && echo "files do exist" || echo "files do not exist" ## This is all we needed to know, so we can break after the first iteration break done ``` -------------------------------- ### Handling Unconventional Function Definitions Source: https://github.com/koalaman/shellcheck/blob/master/shellcheck.1.md Demonstrates how to correctly quote or use 'command' for function names that ShellCheck might misinterpret due to special characters. ```shell function [x!=y] () { [[ $1 ]]; } ``` ```shell '[x!=y]' ``` ```shell command [x!=y] ``` -------------------------------- ### ShellCheck Optional Check: require-double-brackets Source: https://github.com/koalaman/shellcheck/wiki/Optional Requires the use of '[[' instead of '[' in Bash/Ksh for enhanced features. The 'fix' example uses double brackets. ```sh name: require-double-brackets desc: Require [[ and warn about [ in Bash/Ksh example: [ -e /etc/issue ] fix: [[ -e /etc/issue ]] ``` -------------------------------- ### ShellCheck Optional Check: quote-safe-variables Source: https://github.com/koalaman/shellcheck/wiki/Optional Suggests quoting variables that do not contain metacharacters. The 'fix' example demonstrates proper variable quoting. ```sh name: quote-safe-variables desc: Suggest quoting variables without metacharacters example: var=hello; echo $var fix: var=hello; echo "$var" ``` -------------------------------- ### Use `.` instead of `source` in POSIX sh Source: https://github.com/koalaman/shellcheck/wiki/SC3046 Use the `.` command for sourcing scripts in POSIX sh and dash. The `source` command is not supported and will cause errors. ```sh #!/bin/sh source mylib.sh ``` ```sh #!/bin/sh . mylib.sh ``` -------------------------------- ### ShellCheck Optional Check: avoid-nullary-conditions Source: https://github.com/koalaman/shellcheck/wiki/Optional Suggests explicitly using '-n' for non-empty checks. The 'fix' example shows the recommended usage. ```sh name: avoid-nullary-conditions desc: Suggest explicitly using -n in `[ $var ]` example: [ "$var" ] fix: [ -n "$var" ] ``` -------------------------------- ### Shell Script: Correct Space Before Comment Source: https://github.com/koalaman/shellcheck/wiki/SC1099 This corrected code ensures that a space precedes the '#' character, allowing it to be correctly interpreted as the start of a comment. ```sh while sleep 1 do # show time date done ``` -------------------------------- ### Benchmark subshell vs. command group in Shell Source: https://github.com/koalaman/shellcheck/wiki/SC2235 Demonstrates the performance difference between using a subshell `(..)` and a command group `{ ..; }` for repetitive operations. The command group is significantly faster. ```console $ i=0; time for i in {1..10000}; do ([ "$x" ] || [ "$y" ]) && [ "$z" ]; done real 0m7.122s user 0m4.204s sys 0m2.825s ``` ```console $ i=0; time for i in {1..10000}; do { [ "$x" ] || [ "$y" ]; } && [ "$z" ]; done real 0m0.055s user 0m0.055s sys 0m0.000s ``` -------------------------------- ### Executing command in a variable Source: https://github.com/koalaman/shellcheck/wiki/SC2091 Demonstrates how to correctly execute a command stored in a variable. Using command substitution directly on a variable containing a command name can lead to errors. ```sh x=sayhello; $($x) ``` -------------------------------- ### Exception: Concatenated pre-path flags Source: https://github.com/koalaman/shellcheck/wiki/SC2185 This is a false positive scenario. If you concatenate pre-path flags, use individual flags or ignore the message. ```sh find -XLE . ``` -------------------------------- ### Avoid Unquoted `==` in Shell Comparisons Source: https://github.com/koalaman/shellcheck/wiki/SC2284 ShellCheck flags unquoted `==` after a word as problematic. This example shows the problematic code that should be corrected. ```sh if $var == value then echo "Match" fi ``` -------------------------------- ### Split Command Output into Lines with while loop (Bash 3.x+) Source: https://github.com/koalaman/shellcheck/wiki/SC2207 Use a `while` loop with `read` to assign each line of command output to an element in the array. Compatible with Bash 3.x+ and may use temporary files. Error handling needs explicit implementation. ```sh array=() while IFS='' read -r line; do array+=("$line"); done < <(mycommand) ``` -------------------------------- ### Problematic redirection to command names Source: https://github.com/koalaman/shellcheck/wiki/SC2238 These examples show incorrect redirection where output is written to a file named after a command instead of piping to the command. ```sh cat file > tr -d '\''\'' ``` ```sh cat file > rm ``` -------------------------------- ### Compare String Length Methods in Bash Source: https://github.com/koalaman/shellcheck/wiki/SC2000 Demonstrates three methods for checking if a string's length is greater than 1: using `wc -c`, `wc -m`, and the preferred `${#variable}` syntax. Use `${#variable}` for a more direct and readable approach. ```bash #!/usr/bin/env bash if [ "$( echo "$1" | wc -c )" -gt 1 ]; then echo "greater than 1" fi if [ "$( echo "$1" | wc -m )" -gt 1 ]; then echo "greater than 1" fi if [ "${#1}" -gt 1 ]; then echo "greater than 1" fi ``` -------------------------------- ### Problematic find -exec usage Source: https://github.com/koalaman/shellcheck/wiki/SC2150 This example demonstrates an incorrect way to use find -exec with a shell command, which can lead to unexpected behavior. ```sh find . -type f -exec 'cat {} | wc -l' \; ``` -------------------------------- ### Problematic SSH Here Document Expansion Source: https://github.com/koalaman/shellcheck/wiki/SC2087 This example shows a here document where the EOF token is unquoted, causing client-side expansion of variables like $HOSTNAME. ```sh ssh host.example.com << EOF echo "Logged in on $HOSTNAME" EOF ```