views:

112

answers:

3

I have written a small bash script called "isinFile.sh" for checking if the first term given to the script can be found in the file "file.txt":

#!/bin/bash

FILE="file.txt"

if [ `grep -w "$1" $FILE` ]; then 
 echo "true"
else
 echo "false"
fi

However, running the script like

> ./isinFile.sh -x

breaks the script, since -x is interpreted by grep as an option. So I improved my script

#!/bin/bash

FILE="file.txt"

if [ `grep -w -- "$1" $FILE` ]; then 
 echo "true"
else
 echo "false"
fi

using -- as an argument to grep. Now running

> ./isinFile.sh -x
false

works. But is using -- the correct and only way to prevent code/option injection in bash scripts? I have not seen it in the wild, only found it mentioned in ABASH: Finding Bugs in Bash Scripts.

+2  A: 
grep -w -- ...

prevents that interpretation in what follows --

EDIT

(I did not read the last part sorry). Yes, it is the only way. The other way is to avoid it as first part of the search; e.g. ".{0}-x" works too but it is odd., so e.g.

grep -w ".{0}$1" ...

should work too.

ShinTakezou
__important note__ the {} works with extended regex, so add the -E option; (sorry, I've aliased grep to grep -E so didn't noticed at the beginning)
ShinTakezou
You can do this in a basic regex (at least in the implementation of grep I tested with) by escaping the braces: `grep -w ".\{0\}$1" ...`
Gordon Davisson
to ShinTakezou: Do you have another reference where the `--`-option is described? Or do you know the technical term for describing what `--` does, so one can search for it?
asmaier
normally is a common practice on *nix/*nix-like systems, and I think it is common since is the way to tell getopt() to stop parsing for options (getopt() is a posix func that can be used to parse arguments): conventional, as usual: see http://linux.die.net/man/3/getopt and search for the sentence «The special argument "--" forces an end of option-scanning regardless of the scanning mode.»
ShinTakezou
@Gordon Davisson : thanks! but I find excaping of {} () + etc. ugly and prefer -E and consider them special and to have to escape if I do want them not special
ShinTakezou
@ShinTakezou : Thank you for the reference!
asmaier
A: 

Though not applicable in this particular case, another technique can be used to prevent filenames that start with hyphens from being interpreted as options:

rm ./-x

or

rm /path/to/-x
Dennis Williamson
Gordon Davisson
@Gordon: Bash: `[[ $FILE == -* ]] ...`
Dennis Williamson
+1  A: 

There's actually another code injection (or whatever you want to call it) bug in this script: it simply hands the output of grep to the [ (aka test) command, and assumes that'll return true if it's not empty. But if the output is more than one "word" long, [ will treat it as an expression and try to evaluate it. For example, suppose the file contains the line 0 -eq 2 and you search for "0" -- [ will decide that 0 is not equal to 2, and the script will print false despite the fact that it found a match.

The best way to fix this is to use Ignacio Vazquez-Abrams' suggestion (as clarified by Dennis Williamson) -- this completely avoids the parsing problem, and is also faster (since -q makes grep stop searching at the first match). If that option weren't available, another method would be to protect the output with double-quotes: if [ "$(grep -w -- "$1" "$FILE")" ]; then (note that I also used $() instead of backquotes 'cause I find them much easier to read, and quotes around $FILE just in case it contains anything funny, like whitespace).

Gordon Davisson