56

I want to write a Bash script that checks if there is at least one parameter and if there is one, if that parameter is either a 0 or a 1.

This is the script:

#/bin/bash
if (("$#" < 1)) && ( (("$0" != 1)) ||  (("$0" -ne 0q)) ) ; then
    echo this script requires a 1 or 0 as first parameter.
fi
xinput set-prop 12 "Device Enabled" $0

This gives the following errors:

./setTouchpadEnabled: line 2: ((: ./setTouchpadEnabled != 1: syntax error: operand expected (error token is "./setTouchpadEnabled != 1")
./setTouchpadEnabled: line 2: ((: ./setTouchpadEnabled -ne 0q: syntax error: operand expected (error token is "./setTouchpadEnabled -ne 0q")

What am I doing wrong?

2
  • It looks like you are running your script using sh ./setTouchpadEnabled instead of using bash. Commented Jan 25, 2013 at 5:35
  • @jordanm are you referring to the lack of a bang in the shebang line? Commented Oct 18, 2017 at 13:06

4 Answers 4

56

This script works!

#/bin/bash
if [[ ( "$#" < 1 ) || ( !( "$1" == 1 ) && !( "$1" == 0 ) ) ]] ; then
    echo this script requires a 1 or 0 as first parameter.
else
    echo "first parameter is $1"
    xinput set-prop 12 "Device Enabled" $0
fi

But this also works, and in addition keeps the logic of the OP, since the question is about calculations. Here it is with only arithmetic expressions:

#/bin/bash
if (( $# )) && (( $1 == 0 || $1 == 1 )); then
    echo "first parameter is $1"
    xinput set-prop 12 "Device Enabled" $0
else
    echo this script requires a 1 or 0 as first parameter.
fi

The output is the same1:

$ ./tmp.sh 
this script requires a 1 or 0 as first parameter.

$ ./tmp.sh 0
first parameter is 0

$ ./tmp.sh 1
first parameter is 1

$ ./tmp.sh 2
this script requires a 1 or 0 as first parameter.

[1] the second fails if the first argument is a string

Sign up to request clarification or add additional context in comments.

4 Comments

Thank you very much, the error is because the command is xinput and not input
Any particular reason you didn't stick with the arithmetic expressions also used in the question? I.e. use of (( and )).
@user828193: well clearly this is about calculations, so arithmetic expressions are the way to go. Which is why I found it irritating that you changed this aspect of the question in your answer.
@0xC0000022L: You are right! Here it is with arithmetic expressions. I guess I got carried off by the -ne and the comparison to a possibly empty string in the OP's code...
20

Easier solution;

#/bin/bash
if (( ${1:-2} >= 2 )); then
    echo "First parameter must be 0 or 1"
fi
# rest of script...

Output

$ ./test 
First parameter must be 0 or 1
$ ./test 0
$ ./test 1
$ ./test 4
First parameter must be 0 or 1
$ ./test 2
First parameter must be 0 or 1

Explanation

  • (( )) - Evaluates the expression using integers.
  • ${1:-2} - Uses parameter expansion to set a value of 2 if undefined.
  • >= 2 - True if the integer is greater than or equal to two 2.

1 Comment

+1, this exposes and works around a not-great behaviour of the (( command, which assigns the value of 0 to an empty or unset variable.
9

The zeroth parameter of a shell command is the command itself (or sometimes the shell itself). You should be using $1.

(("$#" < 1)) && ( (("$1" != 1)) ||  (("$1" -ne 0q)) )

Your boolean logic is also a bit confused:

(( "$#" < 1 && # If the number of arguments is less than one…
  "$1" != 1 || "$1" -ne 0)) # …how can the first argument possibly be 1 or 0?

This is probably what you want:

(( "$#" )) && (( $1 == 1 || $1 == 0 )) # If true, there is at least one argument and its value is 0 or 1

4 Comments

This is an improvement, thank you. It however still gives me errors: ./setTouchpadEnabled: line 2: ((: != 1: syntax error: operand expected (error token is "!= 1") ./setTouchpadEnabled: line 2: ((: != 0: syntax error: operand expected (error token is "!= 0")
The quotes aren't strictly necessary inside (( )), but they make StackOverflow's highlighting smarter.
@Cheiron I think you misunderstood my comment. Take another look at my answer.
Oh wow, I was indeed doing boolean logic wrong. It still gives me errors, though: ./setTouchpadEnabled: line 2: ((: 0 && ( == 1 || == 0 ) : syntax error: operand expected (error token is "== 1 || == 0 ) ")
8

I know this has been answered, but here's mine just because I think case is an under-appreciated tool. (Maybe because people think it is slow, but it's at least as fast as an if, sometimes faster.)

case "$1" in
    0|1) xinput set-prop 12 "Device Enabled" $1 ;;
      *) echo "This script requires a 1 or 0 as first parameter." ;;
esac

1 Comment

That is nice and clean. Note also the evaluated variable in a case statement is one of those places where you can safely leave it unquoted.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.