From 49ac6c65c4a9251345265732fdbcf11b44cff8c4 Mon Sep 17 00:00:00 2001 From: Vidar Holen Date: Sun, 13 Jan 2019 16:39:01 -0800 Subject: [PATCH] Created SC2245 (markdown) --- SC2245.md | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 SC2245.md diff --git a/SC2245.md b/SC2245.md new file mode 100644 index 0000000..0f12cff --- /dev/null +++ b/SC2245.md @@ -0,0 +1,49 @@ +## -d only applies to the first expansion of this glob. Use a loop to check any/all. + +### Problematic code: + +```sh +if [ -f ksh* ] +then + echo "The file exists" +fi +``` + +### Correct code: + +```sh +for f in ksh* +do + if [ -f "$f" ] + then + echo "Found a matching file: $f" + fi +done +``` +### Rationale: + +Ksh has the curious behavior of ignoring anything after an unrecognized flag to `test`/`[`, which means that file checking operators against globs will effectively apply the operator to the first expansion: + +```sh +[ -f ksh* ] # This +[ -f ksh93u ksh93u.tar ksh93u.tar.gz ] # Becomes this +[ -f ksh93u ] # And is interpreted like this +``` + +This is an issue when you have multiple matches for a glob. Instead of checking some or all, it only checks the first result and ignores the rest. To ensure that all results are considered (either to check that *any* or *all* results match the operator), use a loop explicitly. + +If you really only want to match the first result of the glob expansion as sorted alphabetically in the current locale, you can make this intention explicit: + + matches=( ksh* ) + if [ -f "${matches[0]}" ] + then + echo "The first result is a file" + fi + +### Exceptions: + +If you only care that entries exists, use `-e`. ShellCheck does not warn in this case, since all files resulting from glob expansion necessarily exist. + +### Related resources: + +* Help by adding links to BashFAQ, StackOverflow, man pages, POSIX, etc! \ No newline at end of file