{{Header}} {{title|title= /bin/bash - Proper Whitespace Handling - Whitespace Safety - End-of-Options Parameter Security }} {{#seo: |description=Supporting multiple command line parameters with spaces in wrapper scripts and Use of End-of-Options Parameter (--). }} {{intro| Supporting multiple command line parameters with spaces in wrapper scripts and End-of-Options Parameter (--) for better security. }} = safe echo = TODO * {{VideoLink |videoid=lq98MM2ogBk |text=bash's echo command is broken }} * {{VideoLink |videoid=ft0_cw54qak |text=echo is broken: a follow-up video }} shellcheck bug reports: * [https://github.com/koalaman/shellcheck/issues/2674 Warn on echo "$var" when $var might be -e #2674] * https://github.com/koalaman/shellcheck/issues?q=is%3Aissue+is%3Aopen+echo+in%3Atitle helper-scripts: * https://github.com/Kicksecure/helper-scripts/blob/master/usr/libexec/helper-scripts/safe_echo.sh A drop-in replacement safe_echo would be useful to have. Based on echo: * implementation: abort if first character is a - * advantage: supports colors etc. * disadvantage: break on legitimate output such as "--example" Based on printf: * disadvantage: no support for colors etc. * advantae: does not break if first character is - = Bash Proper Whitespace Handling =
#!/bin/bash

## https://yakking.branchable.com/posts/whitespace-safety/

set -e

app_user=user
lib_dir="/tmp/test/lib/program with space/something spacy"
main_app_dir="/tmp/test/home/user/folder with space/abc"
mkdir -p "$lib_dir"
mkdir -p "$main_app_dir"

declare -a cmd

cmd+=("cp")
cmd+=("-r")
cmd+=("${lib_dir}")
cmd+=("${main_app_dir}/")

"${cmd[@]}"
= Use of End-of-Options Parameter (--) = The end-of-options parameter "--" is crucial because otherwise inputs might be mistaken for command options. This might even be a security risk. Here are examples using the `sponge` command: {{CodeSelect|code= echo test | sponge -a testfilename }} Result: OK. This works because "testfilename" doesn't look like an option. {{CodeSelect|code= echo test | sponge -a --testfilename }} Result: Fail. The command interprets "--testfilename" as a series of options:
sponge: invalid option -- '-'
sponge: invalid option -- 't'
sponge: invalid option -- 'e'
...
test
{{CodeSelect|code= echo test | sponge -a -- --testfilename }} Result: OK. The `--` signals that "--testfilename" is a filename, not an option. Conclusion: * The "--" parameter marks the end of command options. * Use "--" add the end of a command prevent misinterpretation. * This technique is applicable to many Unix/Linux commands, not just sponge. = nounset - Check if Variable Exists =
#!/bin/bash

set -x
set -e
set -o nounset

## Enable for testing.
#unset HOME

if [ -z "${HOME+x}" ]; then
    echo "Error: HOME is not set."
fi

echo "$HOME"
= Safely Using Find with End-Of-Options = Example: Note: Variable could be different. Could be for example --/usr. {{CodeSelect|code= folder_name="/usr" }} {{CodeSelect|code= printf '%s' "${folder_name}" {{!}} find -files0-from - -perm /u=s,g=s -print0 }} Of if safe_echo_nonewline is available from helper-scripts. {{CodeSelect|code= # shellcheck disable=SC1091 source /usr/libexec/helper-scripts/safe_echo.sh safe_echo_nonewline "${folder_name}" {{!}} find -files0-from - -perm /u=s,g=s -print0 }} Not using bash's built-in echo, because it does not support end-of-options ("--"). Not using /usr/bin/echo, because it does not support end-of-options ("--"). {{CodeSelect|code= ## Broken! ## The '-n' option is needed to avoid piping a newline to 'find'. echo -n -- "${folder_name}" {{!}} find -files0-from - -perm /u=s,g=s -print0 }} = misc =
base_name="${file_name##*/}"
file_extension="${base_name##*.}"
= See Also = * https://github.com/anordal/shellharden/blob/master/how_to_do_things_safely_in_bash.md {{Footer}} [[Category: Design]]