### Using wc -c for file size
Source: https://www.shellcheck.net/wiki/SC2012
This example demonstrates using the portable `wc -c` command to get file size, noting potential performance differences and whitespace issues.
```shell
wc -c
$(( $(wc -c < "filename") ))
```
--------------------------------
### Example of space collapsing
Source: https://www.shellcheck.net/wiki/SC2291
Demonstrates how unquoted multiple spaces collapse into a single space when passed as arguments.
```shell
$ echo Hello World
Hello World
```
--------------------------------
### Get ShellCheck Help Information
Source: https://www.shellcheck.net/wiki/directive
Run this command to display the help information for ShellCheck, including a list of supported options and their usage.
```shell
shellcheck --help
```
--------------------------------
### List Optional ShellCheck Checks
Source: https://www.shellcheck.net/wiki/directive
Run this command to see a list of all optional checks supported by ShellCheck, along with examples.
```shell
shellcheck --list-optional
```
--------------------------------
### Example of preserved spaces with quoting
Source: https://www.shellcheck.net/wiki/SC2291
Shows how quoting preserves multiple spaces in the output.
```shell
$ echo "Hello World"
Hello World
```
--------------------------------
### Conditional function definition and call
Source: https://www.shellcheck.net/wiki/SC2218
This example demonstrates defining a function conditionally based on the operating system and then calling it. Ensure the definition is complete before the call.
```sh
case "$(uname -s)" in
Linux) hi() { echo "Hello from Linux"; } ;;
Darwin) hi() { echo "Hello from macOS"; } ;;
*) hi() { echo "Hello from something else"; } ;;
esac
hi
```
--------------------------------
### Problematic sudo redirection examples
Source: https://www.shellcheck.net/wiki/SC2024
These examples demonstrate incorrect usage of sudo with shell redirections, which can lead to permission denied errors.
```shell
# 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
```
--------------------------------
### Handling process substitution failures with wait
Source: https://www.shellcheck.net/wiki/SC2312
This example demonstrates how to handle failures in process substitution by using file descriptor duplication and `wait` to retain and check the exit codes of the substituted processes.
```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"
```
--------------------------------
### Client-side variable expansion example
Source: https://www.shellcheck.net/wiki/SC2029
This code demonstrates how a variable is expanded on the client side before being sent to the server. This is often not the intended behavior for remote command execution.
```shell
ssh host "echo clienthostname"
```
--------------------------------
### Problematic code with `=` starting a command
Source: https://www.shellcheck.net/wiki/SC2275
This code demonstrates the problematic syntax where a variable assignment or command starts with an equals sign, which ShellCheck flags as an error.
```shell
my_variable
=value
```
--------------------------------
### Correct sudo redirection with tee and cat
Source: https://www.shellcheck.net/wiki/SC2024
These examples show the correct way to perform file operations with sudo by piping data through commands like `tee` for writing/appending and `cat` for reading.
```shell
# 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
# Read from a file
sudo cat /etc/shadow | wc -l
```
--------------------------------
### Demonstrate Character Class Case Conversion
Source: https://www.shellcheck.net/wiki/SC2018
This example demonstrates the correct behavior of the 'tr' command using character classes to convert accented characters to uppercase.
```shell
$ tr '[:lower:]' '[:upper:]' <<< "My fiancée ordered a piña colada."
MY FIANCÉE ORDERED A PIÑA COLADA.
```
--------------------------------
### Understanding `&&` and `||` operator associativity
Source: https://www.shellcheck.net/wiki/SC2015
This example illustrates the left-associativity of `&&` and `||` operators, showing how they are evaluated as nested conditional commands.
```shell
((([[ $dryrun ]]) && echo "Would delete file") || rm file)
```
--------------------------------
### Localized String Literal Example
Source: https://www.shellcheck.net/wiki/SC2247
These examples demonstrate how `echo $'(cmd)'` and `echo $'{var}'` are interpreted as localized string literals, not command substitutions. If command substitution was intended, flip the `"` and `$`.
```shell
echo $'(cmd)' # Supposed to be "$(cmd)"
```
```shell
echo $'{var}' # Supposed to be "${var}"
```
--------------------------------
### printf format string interpretation example
Source: https://www.shellcheck.net/wiki/SC2059
This example demonstrates how `printf` interprets format specifiers and escape sequences when a variable is included in the format string, potentially leading to errors.
```shell
coverage='96%'
printf "Unit test coverage: %s\n" "$coverage"
```
```shell
coverage='96%'
printf "Unit test coverage: $coverage\n"
```
--------------------------------
### Find command with exception for tar.gz
Source: https://www.shellcheck.net/wiki/SC2146
This example demonstrates an exception to the SC2146 rule, showing how to decompress all gz files except tar.gz by using grouping and an explicit execution.
```shell
find . -name '*.tar.gz' -o \( -name '*.gz' -exec gzip -d {} + \)
```
--------------------------------
### Parsing units in shell scripting
Source: https://www.shellcheck.net/wiki/SC2262
These examples illustrate different scenarios of shell command parsing units. Understanding these units is crucial for correctly predicting when aliases and other expansions will take effect.
```bash
# A single command followed by a linefeed is one unit
unit 1
```
```bash
# These commands are in the same parsing unit because
# there is no line feed between them
unit 2; unit 2;
```
```bash
# These commands are in the same parsing unit because
# they are part of the same top level brace group
{
unit 3
unit 3
}
```
```bash
# These commands are in the same parsing unit because
# there is no linefeed between the groups.
{
unit 4
}; {
unit 4
}
```
--------------------------------
### Multiline String Exception
Source: https://www.shellcheck.net/wiki/SC1078
This example shows how to correctly define a multiline string using single quotes, which is an exception to the SC1078 warning when intended.
```shell
var='multiline
value'
```
--------------------------------
### Example of ls output with special characters
Source: https://www.shellcheck.net/wiki/SC2012
Demonstrates how `ls` can display filenames with special characters, showing potential ambiguity in output.
```shell
$ 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
```
--------------------------------
### Correct 'do' placement in shell loop
Source: https://www.shellcheck.net/wiki/SC1063
Use a semicolon or line feed before 'do' to correctly start a loop block. This ensures proper shell syntax.
```shell
for file in *; do
echo "$file"
done
# or
for file in *
dO
echo "$file"
done
```
--------------------------------
### Truncating a file with redirection
Source: https://www.shellcheck.net/wiki/SC2189
This example demonstrates a technically valid but potentially confusing use case where a redirection is used to truncate a file. It is recommended to rewrite such code for clarity.
```shell
echo foo | > "$(cat)"
```
--------------------------------
### Parameter expansion starts with unexpected quotes
Source: https://www.shellcheck.net/wiki/SC2301
Use correct syntax for parameter expansion to avoid unexpected quotes. Ensure translated strings are properly formatted.
```shell
echo ${"Hello World"}
```
```shell
echo $"Hello World"
```
--------------------------------
### Get ShellCheck Help Information
Source: https://www.shellcheck.net/wiki/Directive
Displays the manual page for ShellCheck, providing comprehensive information about its usage and options. Alternatively, use 'shellcheck --help'.
```shell
man shellcheck
```
```shell
shellcheck --help
```
--------------------------------
### Demonstrate ASCII Range Case Conversion Issues
Source: https://www.shellcheck.net/wiki/SC2018
This example shows how the 'tr' command with a simple ASCII range fails to convert accented characters to uppercase.
```shell
$ tr 'a-z' 'A-Z' <<< "My fiancée ordered a piña colada."
MY FIANCéE ORDERED A PIñA COLADA.
```
--------------------------------
### find command with basename filter for absolute paths
Source: https://www.shellcheck.net/wiki/SC2012
When using an absolute path for `find`, this example shows how to use `basename` in the filter to exclude the directory itself.
```shell
$ theDir="$HOME/.snapshot"
$ find "$theDir" -maxdepth 1 ! -name "$(basename $theDir)"
/home/matt/.snapshot/rnapdev1-svm_4_05am_6every4hours.2019-04-02_0005
/home/matt/.snapshot/rnapdev1-svm_4_05am_6every4hours.2019-04-02_0405
/home/matt/.snapshot/rnapdev1-svm_4_05am_6every4hours.2019-04-02_0805
/home/matt/.snapshot/rnapdev1-svm_4_05am_6every4hours.2019-04-01_1605
/home/matt/.snapshot/rnapdev1-svm_4_05am_6every4hours.2019-04-01_2005
/home/matt/.snapshot/rnapdev1-svm_4_05am_6every4hours.2019-04-02_1205
/home/matt/.snapshot/snapmirror.1501b4aa-3f82-11e8-9c31-00a098cef13d_2147868328.2019-04-01_190000
```
--------------------------------
### Variable name starts with a number
Source: https://www.shellcheck.net/wiki/SC2282
Variable names in shell scripts cannot start with a digit. Use a letter or underscore instead.
```shell
411toppm=true
```
```shell
_411toppm=true
```
--------------------------------
### Corrected code without cat
Source: https://www.shellcheck.net/wiki/SC2002
These examples show the corrected versions of the problematic code, utilizing input redirection (`<`) or passing the filename directly to the command. This avoids the unnecessary `cat` process.
```shell
< file tr ' ' _ | nl
```
```shell
while IFS= read -r i; do echo "${i%?}"; done < file
```
--------------------------------
### Incorrect command starting with '==='
Source: https://www.shellcheck.net/wiki/SC2274
This code is flagged by SC2274. It's a command that starts with '===', which may have been intended as a comment but is missing the '#' prefix.
```shell
===================== MAIN SECTION =======================
```
--------------------------------
### Bash parameter expansion vs sed for prefix replacement
Source: https://www.shellcheck.net/wiki/SC2001
Demonstrates equivalent prefix replacement using sed and Bash parameter expansion.
```bash
var="foo foo"
# the following two echo's should be equivalent:
echo "$var" | sed 's/^foo/bar/g'
echo "${var/#foo/bar}"
```
--------------------------------
### Find character index and extract substring with parameter expansion
Source: https://www.shellcheck.net/wiki/SC2308
Use parameter expansion to find the index of a character and extract substrings. This example demonstrates finding the position of the first colon and calculating the index based on the length of the part before it.
```shell
# Find character index in string
pos=${input%%:*} pos=$((${#pos}+1))
```
--------------------------------
### Corrected code for piping issues
Source: https://www.shellcheck.net/wiki/SC2216
These corrected examples show how to properly handle command output when the target command does not read from stdin. This includes using `while read` loops, `find -exec`, or logical OR operators.
```shell
ls
```
```shell
cat files | while IFS= read -r file; do rm -- "$file"; done
```
```shell
find . -type f -exec cp {} dir \;
```
```shell
rm file || true
```
--------------------------------
### Quoting command names starting with a dash
Source: https://www.shellcheck.net/wiki/SC2215
If a command name must start with a dash, quote it to explicitly indicate it's a command name and not a flag.
```shell
command "-with-dash"
```
--------------------------------
### Use `--` to end options for safety
Source: https://www.shellcheck.net/wiki/SC2035
Use `-- *glob*` to ensure that globbed filenames, even those starting with a dash, are not interpreted as command-line options. This is a safer alternative for commands like `tar`.
```shell
rm -- *
```
--------------------------------
### SC1134 Error Message Example
Source: https://www.shellcheck.net/wiki/SC1134
This is an example of the error message generated by ShellCheck when it encounters issues parsing the .shellcheckrc file. Ensure the .shellcheckrc file is correctly formatted.
```shell
SC1134 (error): Failed to process foo, line bar: Fix any mentioned problems and try again.
```
--------------------------------
### Correct way to set directory permissions
Source: https://www.shellcheck.net/wiki/SC2174
This code shows the correct approach to ensure all created directories have the specified permissions by separating directory creation and permission setting.
```bash
mkdir -p foo/bar/baz
chmod 0755 foo/bar/baz foo/bar foo
```
--------------------------------
### Use semicolon or linefeed before 'done'
Source: https://www.shellcheck.net/wiki/SC1010
Ensure shell keywords like 'done' are correctly interpreted by placing them at the start of a line, preceded by a semicolon or linefeed. This prevents them from being treated as literal strings.
```shell
for f in *; do echo "$f" done
```
```shell
echo $f is done
```
```shell
for f in *; do echo "$f"; done
```
```shell
echo "$f is done"
```
--------------------------------
### Illustrate command substitution capturing output
Source: https://www.shellcheck.net/wiki/SC2091
Demonstrates how command substitution captures output, which can lead to errors if the captured output is then treated as a command.
```shell
sayhello() { echo "hello world"; }
$(sayhello)
```
--------------------------------
### Resolve merge conflict markers
Source: https://www.shellcheck.net/wiki/SC2273
This example shows typical merge conflict markers left in a script. Ensure merge conflicts are resolved and these markers are removed to avoid syntax errors or unexpected behavior.
```shell
<<<<<<< HEAD
echo "Goodbye World"
=======
echo "Hello World!"
>>>>>>> mybranch
```
--------------------------------
### Get substring by index with expr
Source: https://www.shellcheck.net/wiki/SC2308
Avoid using `expr substr` for getting substrings by index as it has unspecified results and is not portable. Use shell parameter expansion (Bash/Ksh) or `cut` (POSIX) for reliable substring extraction.
```shell
# Get substring by index
col2=$(expr substr "foo bar baz" 8 5)
```
--------------------------------
### Use parameter expansion for simple pattern matching
Source: https://www.shellcheck.net/wiki/SC3057
Demonstrates extracting a substring using parameter expansion to remove a prefix and suffix of a specified length.
```sh
#!/usr/bin/env sh
part="zyxwvutsrqponmlkjihgfedcba"
#echo "${part:5:3}"
part="${part%${part#????????}}"
part="${part#?????}"
printf '%s\n' "${part?}"
```
--------------------------------
### printf behavior with a placeholder
Source: https://www.shellcheck.net/wiki/SC2182
Demonstrates the correct usage of printf with a placeholder and an argument.
```bash
$ printf "hello %s\n" "world"
hello world
```
--------------------------------
### Calculate character index using parameter expansion and string length
Source: https://www.shellcheck.net/wiki/SC2308
Calculate the index of a delimiter by using parameter expansion to get the part of the string before the delimiter and then finding its length. Add 1 to get the 1-based index.
```shell
str="mykey=myvalue"
x=${str%%=*} # Assign x="mystr"
index=$((${#x}+1)) # Add 1 to length of x
```
--------------------------------
### Code walkthrough of parameter expansion for substring extraction
Source: https://www.shellcheck.net/wiki/SC3057
Explains the steps involved in extracting a substring using parameter expansion, detailing prefix and suffix removal.
```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?}"
```
--------------------------------
### Incorrect Shebang Format
Source: https://www.shellcheck.net/wiki/SC1084
The shebang line must start with `#!` followed by the interpreter path. Using `!#` will cause an error.
```shell
!#/bin/sh
echo "Hello World"
```
--------------------------------
### ShellCheck Optional Check: require-double-brackets
Source: https://www.shellcheck.net/wiki/optional
Enforces the use of `[[` and warns against `[` in Bash/Ksh. Example shows the use of single brackets.
```shell
[ -e /etc/issue ]
```
--------------------------------
### Bash brace expansion for multiple file extensions
Source: https://www.shellcheck.net/wiki/SC2102
Demonstrates using brace expansion in Bash to match multiple specific file extensions. This is a more readable and efficient alternative to multiple globs for common cases.
```shell
cat *.{dev,prod,test}.conf
```
--------------------------------
### Alternative `cd` failure handling
Source: https://www.shellcheck.net/wiki/SC2164
Demonstrates alternative ways to handle `cd` failures, including custom messages and conditional execution.
```shell
cd foo || { echo "Failure"; exit 1; }
```
```shell
cd foo || ! echo "Failure"
```
```shell
if cd foo; then echo "Ok"; else echo "Fail"; fi
```
```shell
<(cd foo && cmd)
```
--------------------------------
### ShellCheck Optional Check: quote-safe-variables
Source: https://www.shellcheck.net/wiki/optional
Recommends quoting variables that do not contain metacharacters. Example shows an unquoted variable.
```shell
var=hello; echo $var
```
--------------------------------
### ShellCheck Optional Check: deprecate-which
Source: https://www.shellcheck.net/wiki/optional
Suggests using `command -v` as a modern alternative to `which`. Example shows the usage of `which`.
```shell
which javac
```
--------------------------------
### ShellCheck Optional Check: avoid-negated-conditions
Source: https://www.shellcheck.net/wiki/optional
Recommends removing unnecessary comparison negations. Example demonstrates a negated condition.
```shell
[ ! "$var" -eq 1 ]
```
--------------------------------
### Correct find -exec with sh -c
Source: https://www.shellcheck.net/wiki/SC2150
These examples show the correct way to execute shell commands with find -exec by invoking 'sh -c'. The first is insecure, while the second demonstrates secure handling of filenames using positional parameters.
```shell
find . -type f -exec sh -c 'cat {} | wc -l' \; # Insecure
```
```shell
find . -type f -exec sh -c 'cat "$1" | wc -l' _ {} \; # Secure
```
--------------------------------
### Incorrect numeric comparison
Source: https://www.shellcheck.net/wiki/SC2210
Use (( )) for arithmetic comparisons in bash. This example shows an incorrect attempt to compare numbers.
```shell
if x > 5; then echo "true"; fi
```
--------------------------------
### Use `#!`, not just `!`, for the shebang
Source: https://www.shellcheck.net/wiki/SC1104
The shebang line in shell scripts must start with `#!` to specify the interpreter. Using only `!` is incorrect and will cause errors.
```shell
#!/bin/sh
echo "Hello"
```
```shell
!/bin/sh
echo "Hello"
```
--------------------------------
### Demonstrate sh -c with Arguments
Source: https://www.shellcheck.net/wiki/SC2014
Illustrates how sh -c can be used with arguments, where '_' becomes $0 and the subsequent argument becomes $1 within the inlined script. This is a common pattern when using sh -c with find -exec.
```shell
$ sh -c 'echo "$1 is in $(dirname "$1")"' _ "mydir/myfile"
```
--------------------------------
### Incorrect file descriptor redirection
Source: https://www.shellcheck.net/wiki/SC2210
Ensure file descriptor redirections are correctly formatted. This example shows a malformed redirection.
```shell
foo > /dev/null 2>1
```
--------------------------------
### Apply Directives to Entire Script with Dummy Command
Source: https://www.shellcheck.net/wiki/directive
Use a dummy command like `true` or `:` with directives to apply them to the entire script when they cannot be placed immediately after the shebang.
```shell
# This directive applies to the entire script
# shellcheck disable=2086
true
# This directive only applies to this function
# shellcheck disable=2043
f() {
...
}
```
--------------------------------
### Problematic ash script
Source: https://www.shellcheck.net/wiki/SC2187
This is an example of an ash script that will trigger the SC2187 warning because ShellCheck checks ash scripts as dash.
```bash
#!/bin/ash
echo "Hello World"
```
--------------------------------
### Demonstrate $ expansion issues in arithmetic
Source: https://www.shellcheck.net/wiki/SC2004
Illustrates how wrapping a variable in $ within an arithmetic context can lead to incorrect evaluation. The variable's content is treated as a string expression rather than its numerical value.
```shell
$ a='1+1'
$ echo $(($a * 5)) # becomes 1+1*5
6
$ echo $((a * 5)) # evaluates as (1+1)*5
10
```
--------------------------------
### Command substitution with variable
Source: https://www.shellcheck.net/wiki/SC2091
Example of command substitution used with a variable holding a command name, leading to potential errors.
```shell
x=sayhello; $($x)
```
--------------------------------
### POSIX sh for multiple file extensions
Source: https://www.shellcheck.net/wiki/SC2102
Illustrates the POSIX-compliant way to match multiple file extensions by listing each glob pattern separately. This approach is compatible with all POSIX shells.
```shell
cat *.dev.conf *.prod.conf *.test.conf
```
--------------------------------
### ShellCheck Optional Check: useless-use-of-cat
Source: https://www.shellcheck.net/wiki/optional
Identifies 'Useless Use Of Cat' (UUOC) patterns. Example demonstrates UUOC with `cat` and `grep`.
```shell
cat foo | grep bar
```
--------------------------------
### Correct parameter expansion `${x}`
Source: https://www.shellcheck.net/wiki/SC2298
Use the standard ${VAR:-default} syntax for parameter expansion with a default value.
```shell
retries=${RETRIES:-3}
```
--------------------------------
### Use mktemp instead of deprecated tempfile
Source: https://www.shellcheck.net/wiki/SC2186
Avoid using the deprecated `tempfile` command. Use `mktemp` for creating temporary files as it is more portable and widely supported.
```shell
tmp=$(tempfile)
```
```shell
tmp=$(mktemp)
```
--------------------------------
### ShellCheck Optional Check: check-unassigned-uppercase
Source: https://www.shellcheck.net/wiki/optional
Warns if uppercase variables are used without being assigned. Example shows an unassigned uppercase variable.
```shell
echo $VAR
```
--------------------------------
### Illustrate for loop word splitting and globbing
Source: https://www.shellcheck.net/wiki/SC2013
Demonstrates how a `for` loop processes a file containing words and a wildcard, showing the resulting word splitting and glob expansion.
```shell
foo *
bar
```
--------------------------------
### ShellCheck Optional Check: avoid-nullary-conditions
Source: https://www.shellcheck.net/wiki/optional
Suggests using `-n` explicitly with `[` for non-empty string checks. Example shows a nullary condition.
```shell
[ "$var" ]
```
--------------------------------
### Illustrate direct command execution
Source: https://www.shellcheck.net/wiki/SC2091
Shows how directly calling a function or command executes it without capturing its output.
```shell
sayhello() { echo "hello world"; }
sayhello
```
--------------------------------
### ShellCheck Optional Check: add-default-case
Source: https://www.shellcheck.net/wiki/optional
Suggests adding a default case to `case` statements. Example shows a basic `case` statement.
```shell
case $? in 0) echo 'Success';; esac
```
--------------------------------
### Correct 'ln' command with specified destination
Source: https://www.shellcheck.net/wiki/SC2226
This snippet demonstrates the correct way to use the 'ln' command, explicitly specifying both the source file and the destination directory. For linking into the current directory, use '.' as the destination.
```shell
ln "$file" "$dir"
```
```shell
ln /foo/bar/baz .
```
--------------------------------
### Correct usage of `command -v` and `hash`
Source: https://www.shellcheck.net/wiki/SC2230
Use `command -v` for checking command existence and path, or `hash` for checking existence without obtaining a path. These are POSIX standard alternatives to `which`.
```shell
# For the path of a single, unaliased, external command,
# or to check whether this will just "run" in this shell:
command -v grep
# To check whether commands exist, without obtaining a reusable path:
hash grep
```
--------------------------------
### Missing Space Before Comment Marker
Source: https://www.shellcheck.net/wiki/SC1099
Ensure a space precedes the '#' character when starting a comment. This is necessary for the shell to correctly interpret the line as a comment.
```shell
while sleep 1
do# show time
date
done
```
```shell
while sleep 1
do # show time
date
done
```
--------------------------------
### Bash extglob for multiple file extensions
Source: https://www.shellcheck.net/wiki/SC2102
Shows how to use Bash's extended globbing feature (`extglob`) with an OR pattern to match multiple file extensions. Ensure `shopt -s extglob` is enabled for this to work.
```shell
cat *.@(dev|prod|test).conf
```
--------------------------------
### Get last argument in POSIX sh
Source: https://www.shellcheck.net/wiki/SC3057
This method retrieves the last argument passed to a script and works in very old Bourne shell versions.
```sh
#!/bin/sh
for argument in "$@"; do
: # :, also called as `true`, is a no-op here
done
printf '%s\n' "${argument-}"
```
--------------------------------
### Alternative methods for writing to files with sudo
Source: https://www.shellcheck.net/wiki/SC2024
These snippets offer alternative commands like `dd` and `sed` to achieve file truncation with sudo, similar to `tee`.
```shell
echo 'data' | sudo dd of=file
```
```shell
echo 'data' | sudo sed 'w file'
```
--------------------------------
### Use `elif` instead of `elseif` in shell scripts
Source: https://www.shellcheck.net/wiki/SC1131
Use `elif` to start another branch in shell conditional statements. `elseif` is not a valid keyword.
```shell
if false
then
echo "hi"
elseif true
then
echo "ho"
fi
```
```shell
if false
then
echo "hi"
elif true
then
echo "ho"
fi
```
--------------------------------
### ShellCheck Optional Check: check-set-e-suppressed
Source: https://www.shellcheck.net/wiki/optional
Notifies when `set -e` is suppressed during function invocation. Example demonstrates `set -e` suppression within a function.
```shell
set -e; func() { cp *.txt ~/backup; rm *.txt; }; func && echo ok
```
--------------------------------
### Simple while read loop for file input
Source: https://www.shellcheck.net/wiki/SC2013
The most straightforward way to loop through a file line by line using a `while read` loop, without any filtering. Also shows an alternative for reading from a variable.
```shell
while IFS= read -r line
do
echo "Line: $line"
done < file
```
```shell
# or: done <<< "$variable"
```
--------------------------------
### ShellCheck Optional Check: check-extra-masked-returns
Source: https://www.shellcheck.net/wiki/optional
Checks for additional scenarios where exit codes might be masked. Example shows a potentially masked exit code.
```shell
rm -r "$(get_chroot_dir)/home"
```
--------------------------------
### Using /usr/bin/env for interpreter path
Source: https://www.shellcheck.net/wiki/SC2239
When the exact path to an interpreter is unknown or varies, use '/usr/bin/env' followed by the interpreter name. This searches the user's PATH for the executable, offering flexibility while adhering to best practices.
```shell
#!/usr/bin/env bash
echo "Hello World"
```
--------------------------------
### Identical HTML output with and without unnecessary quotes
Source: https://www.shellcheck.net/wiki/SC2140
These examples demonstrate that unnecessary quotes around HTML attributes do not change the output, but can trigger SC2140.
```shell
echo "
" > file.html
```
```shell
echo "
" > file.html
```
--------------------------------
### Correctly running commands as another user with `sudo`
Source: https://www.shellcheck.net/wiki/SC2117
This code shows the correct way to execute a command as another user using `sudo`. `sudo` is preferred as it requires less quoting and can be configured for passwordless execution.
```shell
whoami
sudo whoami
```
--------------------------------
### Alternative using `hash`
Source: https://www.shellcheck.net/wiki/SC2230
The `hash` command can be used as an alternative to `command -v` to observe standard failure behavior when checking for command existence.
```shell
$ hash
```
--------------------------------
### Distinguish Directives from Comments
Source: https://www.shellcheck.net/wiki/SC1126
If a comment mentions ShellCheck but is not a directive, rewrite or capitalize it to avoid misinterpretation. This example shows a comment about variable naming conventions.
```shell
var=1 # ShellCheck encourages lowercase variable names
```
--------------------------------
### Find command with redirection applied to entire command
Source: https://www.shellcheck.net/wiki/SC2227
Illustrates how a redirection in a find command applies to the entire command, not just a specific action.
```shell
{
find . -name '*.ppm' -exec pnmtopng {} \;
} > {}.png
```
--------------------------------
### Incorrect 'do' placement in shell loop
Source: https://www.shellcheck.net/wiki/SC1063
Ensure 'do' starts a new line or statement in shell loops. Incorrect placement can lead to syntax errors.
```shell
for file in * do
echo "$file"
done
```
--------------------------------
### Performance Comparison: Subshell vs. Direct Condition
Source: https://www.shellcheck.net/wiki/SC2233
Demonstrates the significant performance difference between using subshells with parentheses and direct conditional checks in a loop.
```shell
$ i=0; time while ( [ "$i" -lt 10000 ] ); do i=$((i+1)); done
real 0m6.998s
user 0m3.453s
sys 0m3.464s
```
```shell
$ i=0; time while [ "$i" -lt 10000 ]; do i=$((i+1)); done
real 0m0.055s
user 0m0.054s
sys 0m0.001s
```
--------------------------------
### Variable assignment with inner quotes
Source: https://www.shellcheck.net/wiki/SC2223
When quoting default assignments, ensure inner quotes are correctly handled. This example shows assigning 'foo' with and without quotes.
```shell
: ${var:='foo'} # Assigns foo without quotes
```
```shell
: "${var:='foo'}" # Assigns 'foo' with quotes
```
--------------------------------
### Compare string length methods in Bash
Source: https://www.shellcheck.net/wiki/SC2000
Demonstrates three ways to check if the length of the first argument is greater than 1: using `wc -c`, `wc -m`, and `${#1}`. Prefer `${#1}` for efficiency.
```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
```
--------------------------------
### Common cases where SC2086 warning may seem unnecessary
Source: https://www.shellcheck.net/wiki/SC2086
These examples show cases where the SC2086 warning might appear, but quoting is still recommended for robustness or to avoid potential issues like Denial of Service (DoS) with specific patterns.
```shell
cmd <<< $var # Requires quoting on Bash 3 (but not 4+)
```
```shell
: ${var=default} # Should be quoted to avoid DoS when var='*/*/*/*/*/*'
```
--------------------------------
### Problematic code with literal carriage return
Source: https://www.shellcheck.net/wiki/SC1017
This example shows a shell script with Windows-style line endings, where `^M` indicates a literal carriage return character.
```shell
$ cat -v myscript
#!/bin/sh^M
echo "Hello World"^M
```
--------------------------------
### Iterate over files using globs
Source: https://www.shellcheck.net/wiki/SC2045
Correct and robust way to iterate over files using shell globs. Includes a check for the case where no matching files are found.
```shell
for f in *.wav
do
[[ -e "$f" ]] || break # handle the case of no *.wav files
echo "$f"
done
```
--------------------------------
### Incorrect unary condition syntax
Source: https://www.shellcheck.net/wiki/SC1019
Unary test operators require an operand. This example shows incorrect usage where '-x' is not followed by a file or other valid operand.
```shell
[ -x ]
```
--------------------------------
### Simple POSIX find -exec
Source: https://www.shellcheck.net/wiki/SC2044
For simple commands without aggregation or shell script bodies, `find -exec` is a POSIX-compatible and efficient solution. It directly executes a command for each found file.
```shell
# Simple and POSIX
find mydir -name '*.mp3' -exec play {} \;
```
--------------------------------
### Get substring by index with POSIX cut
Source: https://www.shellcheck.net/wiki/SC2308
Use `cut -c` for POSIX-compliant substring extraction by character index. Be cautious if the input can contain multiple lines.
```shell
# Get substring by index (POSIX)
col2="$(printf 'foo bar baz\n' | cut -c 8-12)"
```
--------------------------------
### ls -c1 output for directory listing
Source: https://www.shellcheck.net/wiki/SC2012
Shows the output of `ls -c1` for a directory, listing filenames with potential formatting differences.
```shell
$ ls -c1 .snapshot
rnapdev1-svm_4_05am_6every4hours.2019-04-01_1605
rnapdev1-svm_4_05am_6every4hours.2019-04-01_2005
rnapdev1-svm_4_05am_6every4hours.2019-04-02_0005
rnapdev1-svm_4_05am_6every4hours.2019-04-02_0405
rnapdev1-svm_4_05am_6every4hours.2019-04-02_0805
rnapdev1-svm_4_05am_6every4hours.2019-04-02_1205
snapmirror.1501b4aa-3f82-11e8-9c31-00a098cef13d_2147868328.2019-04-01_190000
```
--------------------------------
### SC1041 and SC1042 error messages
Source: https://www.shellcheck.net/wiki/SC1041
Companion SC1041 and SC1042 errors may appear together, pointing to the start of the here document rather than the specific line with the terminator issue.
```sh
In foo line 4:
Hello
^-- SC1041: Found 'eof' further down, but not on a separate line.
^-- SC1042: Close matches include '-eof' (!= 'eof').
```
--------------------------------
### Buffer output with temporary file and cat
Source: https://www.shellcheck.net/wiki/SC2005
Use a temporary file and 'cat' to buffer potentially large output without using more memory or modifying the content. This is an alternative to 'echo "$(cmd)"' when dealing with significant amounts of data.
```shell
# Buffer up potentially large output without using more memory or modifying the content in any way
cmd > file.tmp
cat file.tmp
```
--------------------------------
### Intentional Fork Bomb Example
Source: https://www.shellcheck.net/wiki/SC2264
ShellCheck does not warn about intentional fork bombs. If a fork bomb triggers this warning, add a leading command or condition to ignore the issue.
```bash
:() { true && :|: & }
```
--------------------------------
### `command -v` behavior with multiple arguments
Source: https://www.shellcheck.net/wiki/SC2230
Demonstrates that `command -v` exits with 0 if any of the provided commands exist, unlike `which` which might be expected to fail if not all exist. This check is opt-in.
```shell
# grep is in /usr/bin/grep
# foobar is not in path
#
$ command -v -- grep foobar; echo $?
```
--------------------------------
### Problematic glob range expression
Source: https://www.shellcheck.net/wiki/SC2102
This example shows a glob range expression that incorrectly attempts to match a range of numbers by repeating characters. This will only match a single digit.
```shell
echo [100-999].txt
```
--------------------------------
### Correct Shebang Placement
Source: https://www.shellcheck.net/wiki/SC1128
This code shows the correct way to place a shebang line, ensuring it is the first line of the script. Comments should follow the shebang.
```bash
#!/bin/bash
# Copyright 2018 Foobar, All rights reserved
```
--------------------------------
### Example of `eval` exploit with unquoted variables
Source: https://www.shellcheck.net/wiki/SC2089
Demonstrates a severe security vulnerability that can arise from using `eval` with unquoted variables, especially within loops processing filenames.
```shell
for f in *.txt; do
args="-lh '$1'" # Example security exploit
eval ls "$args" # Do not copy and use
done
```
--------------------------------
### Handle multiple files from command substitution with a loop
Source: https://www.shellcheck.net/wiki/SC2046
If a command substitution outputs multiple files, use a while loop to process each line individually and prevent word splitting.
```shell
getfilename | while IFS='' read -r line
do
ls -l "$line"
done
```
--------------------------------
### Correct unary condition syntax
Source: https://www.shellcheck.net/wiki/SC1019
Unary test operators must be followed by an operand. This example demonstrates the correct usage by providing 'myfile' as the operand for the '-x' test.
```shell
[ -x "myfile" ]
```
--------------------------------
### Indirect expansion using bash
Source: https://www.shellcheck.net/wiki/SC3053
Switch to a shell like bash that supports indirect expansion for a straightforward solution.
```bash
#!/bin/bash
name="PATH"
echo "${!name}"
```