Binary operator expected - quoting question for shell script args

Clash Royale CLAN TAG#URR8PPP
up vote
1
down vote
favorite
I have a question on how I'm adding arguments when executing a shell script.
I have a simple script which helps me block ip ranges:
~/block_ip.sh:
if [ ! $3 ]
then
 echo "usage ~/block_ip.sh (DROP/ACCEPT) '0.0.0.0' 'amsterdam'"
 exit 1
fi
echo "adding $3"
sudo iptables -I INPUT -s $2 -j $1 -m comment --comment "$3"
If I execute this without arguments the output is as expected:
~$ ./block_ip.sh
usage ~/block_ip.sh (DROP/ACCEPT) '0.0.0.0' 'amsterdam'
However the spaces seem to be the cause of the unexpected output of "binary operator expected":
~$ ./block_ip.sh DROP '1.0.0.0/8' 'south brisbane qld'
./block_ip.sh: line 1: [: brisbane: binary operator expected
adding south brisbane au
But then it adds it despite the unexpected output:
Chain INPUT (policy ACCEPT)
num target prot opt source destination
1 DROP all -- 1.0.0.0/8 anywhere /* south brisbane au */
If this is a quoting issue, how do I form the arguments (without using backslashes to escape the spaces)? Of course, I expect I may need a change to the script, that is an acceptable solution, too.
bash shell-script arguments whitespace
add a comment |Â
up vote
1
down vote
favorite
I have a question on how I'm adding arguments when executing a shell script.
I have a simple script which helps me block ip ranges:
~/block_ip.sh:
if [ ! $3 ]
then
 echo "usage ~/block_ip.sh (DROP/ACCEPT) '0.0.0.0' 'amsterdam'"
 exit 1
fi
echo "adding $3"
sudo iptables -I INPUT -s $2 -j $1 -m comment --comment "$3"
If I execute this without arguments the output is as expected:
~$ ./block_ip.sh
usage ~/block_ip.sh (DROP/ACCEPT) '0.0.0.0' 'amsterdam'
However the spaces seem to be the cause of the unexpected output of "binary operator expected":
~$ ./block_ip.sh DROP '1.0.0.0/8' 'south brisbane qld'
./block_ip.sh: line 1: [: brisbane: binary operator expected
adding south brisbane au
But then it adds it despite the unexpected output:
Chain INPUT (policy ACCEPT)
num target prot opt source destination
1 DROP all -- 1.0.0.0/8 anywhere /* south brisbane au */
If this is a quoting issue, how do I form the arguments (without using backslashes to escape the spaces)? Of course, I expect I may need a change to the script, that is an acceptable solution, too.
bash shell-script arguments whitespace
1
If your goal in testing$3is just to be sure that there are three parameters, then you can use the simpler$#shell variable, which holds the number of parameters, eg.if [ $# -ne 3 ].
â user1404316
Feb 8 at 17:45
@user1404316 very useful - thanks
â WEBjuju
Feb 8 at 21:10
add a comment |Â
up vote
1
down vote
favorite
up vote
1
down vote
favorite
I have a question on how I'm adding arguments when executing a shell script.
I have a simple script which helps me block ip ranges:
~/block_ip.sh:
if [ ! $3 ]
then
 echo "usage ~/block_ip.sh (DROP/ACCEPT) '0.0.0.0' 'amsterdam'"
 exit 1
fi
echo "adding $3"
sudo iptables -I INPUT -s $2 -j $1 -m comment --comment "$3"
If I execute this without arguments the output is as expected:
~$ ./block_ip.sh
usage ~/block_ip.sh (DROP/ACCEPT) '0.0.0.0' 'amsterdam'
However the spaces seem to be the cause of the unexpected output of "binary operator expected":
~$ ./block_ip.sh DROP '1.0.0.0/8' 'south brisbane qld'
./block_ip.sh: line 1: [: brisbane: binary operator expected
adding south brisbane au
But then it adds it despite the unexpected output:
Chain INPUT (policy ACCEPT)
num target prot opt source destination
1 DROP all -- 1.0.0.0/8 anywhere /* south brisbane au */
If this is a quoting issue, how do I form the arguments (without using backslashes to escape the spaces)? Of course, I expect I may need a change to the script, that is an acceptable solution, too.
bash shell-script arguments whitespace
I have a question on how I'm adding arguments when executing a shell script.
I have a simple script which helps me block ip ranges:
~/block_ip.sh:
if [ ! $3 ]
then
 echo "usage ~/block_ip.sh (DROP/ACCEPT) '0.0.0.0' 'amsterdam'"
 exit 1
fi
echo "adding $3"
sudo iptables -I INPUT -s $2 -j $1 -m comment --comment "$3"
If I execute this without arguments the output is as expected:
~$ ./block_ip.sh
usage ~/block_ip.sh (DROP/ACCEPT) '0.0.0.0' 'amsterdam'
However the spaces seem to be the cause of the unexpected output of "binary operator expected":
~$ ./block_ip.sh DROP '1.0.0.0/8' 'south brisbane qld'
./block_ip.sh: line 1: [: brisbane: binary operator expected
adding south brisbane au
But then it adds it despite the unexpected output:
Chain INPUT (policy ACCEPT)
num target prot opt source destination
1 DROP all -- 1.0.0.0/8 anywhere /* south brisbane au */
If this is a quoting issue, how do I form the arguments (without using backslashes to escape the spaces)? Of course, I expect I may need a change to the script, that is an acceptable solution, too.
bash shell-script arguments whitespace
edited Feb 8 at 15:52
ilkkachu
49.6k673137
49.6k673137
asked Feb 8 at 15:47
WEBjuju
410211
410211
1
If your goal in testing$3is just to be sure that there are three parameters, then you can use the simpler$#shell variable, which holds the number of parameters, eg.if [ $# -ne 3 ].
â user1404316
Feb 8 at 17:45
@user1404316 very useful - thanks
â WEBjuju
Feb 8 at 21:10
add a comment |Â
1
If your goal in testing$3is just to be sure that there are three parameters, then you can use the simpler$#shell variable, which holds the number of parameters, eg.if [ $# -ne 3 ].
â user1404316
Feb 8 at 17:45
@user1404316 very useful - thanks
â WEBjuju
Feb 8 at 21:10
1
1
If your goal in testing
$3 is just to be sure that there are three parameters, then you can use the simpler $# shell variable, which holds the number of parameters, eg. if [ $# -ne 3 ].â user1404316
Feb 8 at 17:45
If your goal in testing
$3 is just to be sure that there are three parameters, then you can use the simpler $# shell variable, which holds the number of parameters, eg. if [ $# -ne 3 ].â user1404316
Feb 8 at 17:45
@user1404316 very useful - thanks
â WEBjuju
Feb 8 at 21:10
@user1404316 very useful - thanks
â WEBjuju
Feb 8 at 21:10
add a comment |Â
 1 Answer
 1
 
active
oldest
votes
up vote
5
down vote
accepted
Yep, that's a quoting issue: [ ! $3 ] expands to [ ! south brisbane qld ] (four arguments between [ and ]). And when it sees four arguments, with the first one a !, [ expects to see something like [ ! arg1 op arg2 ] where op is a binary operator. (this, again is one of the things different between [ .. ] and [[ .. ]]; see this Q and also this Q)
brisbane isn't a valid operator, so it complains and returns 2, which is falsy so the statements inside the if are not executed. To tell the difference between an error and a regular failing test, you'd need to explicitly test the return value against 2. 
On the other hand, if $3 is empty, then the test becomes [ ! ], a one-argument test that checks if the only argument is nonempty (it is, it's the one-character string !). In that case, it works as intended, though perhaps not for the reason you'd expect.
You want [ ! "$3" ] or [ -z "$3" ] to keep the string as one argument for [. 
Of course you could also invert the sense of the test, and do the actual work inside the if, so that an error in the test would avoid running the main commands. But that would make the code structure a bit more unclear.
nice - so the reason it is working then is that even though it errors, $3 isn't empty so it passes the ! test and then i have it quoted in theiptablescommand so its expansion to include spaces is handled already - is that right?
â WEBjuju
Feb 8 at 15:55
and they'll want to quote the parameters in the iptables line as well
â Jeff Schaller
Feb 8 at 16:00
@WEBjuju, ah yes, I meant to write about that, edited why it works. And yes, you had the quotes in theiptablescommand so there it works fine.
â ilkkachu
Feb 8 at 16:04
@ilkkachu gotcha, yes, it seems silly on my end. somehow i knew it subconsciously but couldn't bring forth the knowledge to a working solution. i have somehow muddled through without knowing this basic tenant until now, but i just seriously leveled up. much thanks!
â WEBjuju
Feb 8 at 16:14
add a comment |Â
 1 Answer
 1
 
active
oldest
votes
 1 Answer
 1
 
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
5
down vote
accepted
Yep, that's a quoting issue: [ ! $3 ] expands to [ ! south brisbane qld ] (four arguments between [ and ]). And when it sees four arguments, with the first one a !, [ expects to see something like [ ! arg1 op arg2 ] where op is a binary operator. (this, again is one of the things different between [ .. ] and [[ .. ]]; see this Q and also this Q)
brisbane isn't a valid operator, so it complains and returns 2, which is falsy so the statements inside the if are not executed. To tell the difference between an error and a regular failing test, you'd need to explicitly test the return value against 2. 
On the other hand, if $3 is empty, then the test becomes [ ! ], a one-argument test that checks if the only argument is nonempty (it is, it's the one-character string !). In that case, it works as intended, though perhaps not for the reason you'd expect.
You want [ ! "$3" ] or [ -z "$3" ] to keep the string as one argument for [. 
Of course you could also invert the sense of the test, and do the actual work inside the if, so that an error in the test would avoid running the main commands. But that would make the code structure a bit more unclear.
nice - so the reason it is working then is that even though it errors, $3 isn't empty so it passes the ! test and then i have it quoted in theiptablescommand so its expansion to include spaces is handled already - is that right?
â WEBjuju
Feb 8 at 15:55
and they'll want to quote the parameters in the iptables line as well
â Jeff Schaller
Feb 8 at 16:00
@WEBjuju, ah yes, I meant to write about that, edited why it works. And yes, you had the quotes in theiptablescommand so there it works fine.
â ilkkachu
Feb 8 at 16:04
@ilkkachu gotcha, yes, it seems silly on my end. somehow i knew it subconsciously but couldn't bring forth the knowledge to a working solution. i have somehow muddled through without knowing this basic tenant until now, but i just seriously leveled up. much thanks!
â WEBjuju
Feb 8 at 16:14
add a comment |Â
up vote
5
down vote
accepted
Yep, that's a quoting issue: [ ! $3 ] expands to [ ! south brisbane qld ] (four arguments between [ and ]). And when it sees four arguments, with the first one a !, [ expects to see something like [ ! arg1 op arg2 ] where op is a binary operator. (this, again is one of the things different between [ .. ] and [[ .. ]]; see this Q and also this Q)
brisbane isn't a valid operator, so it complains and returns 2, which is falsy so the statements inside the if are not executed. To tell the difference between an error and a regular failing test, you'd need to explicitly test the return value against 2. 
On the other hand, if $3 is empty, then the test becomes [ ! ], a one-argument test that checks if the only argument is nonempty (it is, it's the one-character string !). In that case, it works as intended, though perhaps not for the reason you'd expect.
You want [ ! "$3" ] or [ -z "$3" ] to keep the string as one argument for [. 
Of course you could also invert the sense of the test, and do the actual work inside the if, so that an error in the test would avoid running the main commands. But that would make the code structure a bit more unclear.
nice - so the reason it is working then is that even though it errors, $3 isn't empty so it passes the ! test and then i have it quoted in theiptablescommand so its expansion to include spaces is handled already - is that right?
â WEBjuju
Feb 8 at 15:55
and they'll want to quote the parameters in the iptables line as well
â Jeff Schaller
Feb 8 at 16:00
@WEBjuju, ah yes, I meant to write about that, edited why it works. And yes, you had the quotes in theiptablescommand so there it works fine.
â ilkkachu
Feb 8 at 16:04
@ilkkachu gotcha, yes, it seems silly on my end. somehow i knew it subconsciously but couldn't bring forth the knowledge to a working solution. i have somehow muddled through without knowing this basic tenant until now, but i just seriously leveled up. much thanks!
â WEBjuju
Feb 8 at 16:14
add a comment |Â
up vote
5
down vote
accepted
up vote
5
down vote
accepted
Yep, that's a quoting issue: [ ! $3 ] expands to [ ! south brisbane qld ] (four arguments between [ and ]). And when it sees four arguments, with the first one a !, [ expects to see something like [ ! arg1 op arg2 ] where op is a binary operator. (this, again is one of the things different between [ .. ] and [[ .. ]]; see this Q and also this Q)
brisbane isn't a valid operator, so it complains and returns 2, which is falsy so the statements inside the if are not executed. To tell the difference between an error and a regular failing test, you'd need to explicitly test the return value against 2. 
On the other hand, if $3 is empty, then the test becomes [ ! ], a one-argument test that checks if the only argument is nonempty (it is, it's the one-character string !). In that case, it works as intended, though perhaps not for the reason you'd expect.
You want [ ! "$3" ] or [ -z "$3" ] to keep the string as one argument for [. 
Of course you could also invert the sense of the test, and do the actual work inside the if, so that an error in the test would avoid running the main commands. But that would make the code structure a bit more unclear.
Yep, that's a quoting issue: [ ! $3 ] expands to [ ! south brisbane qld ] (four arguments between [ and ]). And when it sees four arguments, with the first one a !, [ expects to see something like [ ! arg1 op arg2 ] where op is a binary operator. (this, again is one of the things different between [ .. ] and [[ .. ]]; see this Q and also this Q)
brisbane isn't a valid operator, so it complains and returns 2, which is falsy so the statements inside the if are not executed. To tell the difference between an error and a regular failing test, you'd need to explicitly test the return value against 2. 
On the other hand, if $3 is empty, then the test becomes [ ! ], a one-argument test that checks if the only argument is nonempty (it is, it's the one-character string !). In that case, it works as intended, though perhaps not for the reason you'd expect.
You want [ ! "$3" ] or [ -z "$3" ] to keep the string as one argument for [. 
Of course you could also invert the sense of the test, and do the actual work inside the if, so that an error in the test would avoid running the main commands. But that would make the code structure a bit more unclear.
edited Feb 8 at 16:06
answered Feb 8 at 15:54
ilkkachu
49.6k673137
49.6k673137
nice - so the reason it is working then is that even though it errors, $3 isn't empty so it passes the ! test and then i have it quoted in theiptablescommand so its expansion to include spaces is handled already - is that right?
â WEBjuju
Feb 8 at 15:55
and they'll want to quote the parameters in the iptables line as well
â Jeff Schaller
Feb 8 at 16:00
@WEBjuju, ah yes, I meant to write about that, edited why it works. And yes, you had the quotes in theiptablescommand so there it works fine.
â ilkkachu
Feb 8 at 16:04
@ilkkachu gotcha, yes, it seems silly on my end. somehow i knew it subconsciously but couldn't bring forth the knowledge to a working solution. i have somehow muddled through without knowing this basic tenant until now, but i just seriously leveled up. much thanks!
â WEBjuju
Feb 8 at 16:14
add a comment |Â
nice - so the reason it is working then is that even though it errors, $3 isn't empty so it passes the ! test and then i have it quoted in theiptablescommand so its expansion to include spaces is handled already - is that right?
â WEBjuju
Feb 8 at 15:55
and they'll want to quote the parameters in the iptables line as well
â Jeff Schaller
Feb 8 at 16:00
@WEBjuju, ah yes, I meant to write about that, edited why it works. And yes, you had the quotes in theiptablescommand so there it works fine.
â ilkkachu
Feb 8 at 16:04
@ilkkachu gotcha, yes, it seems silly on my end. somehow i knew it subconsciously but couldn't bring forth the knowledge to a working solution. i have somehow muddled through without knowing this basic tenant until now, but i just seriously leveled up. much thanks!
â WEBjuju
Feb 8 at 16:14
nice - so the reason it is working then is that even though it errors, $3 isn't empty so it passes the ! test and then i have it quoted in the
iptables command so its expansion to include spaces is handled already - is that right?â WEBjuju
Feb 8 at 15:55
nice - so the reason it is working then is that even though it errors, $3 isn't empty so it passes the ! test and then i have it quoted in the
iptables command so its expansion to include spaces is handled already - is that right?â WEBjuju
Feb 8 at 15:55
and they'll want to quote the parameters in the iptables line as well
â Jeff Schaller
Feb 8 at 16:00
and they'll want to quote the parameters in the iptables line as well
â Jeff Schaller
Feb 8 at 16:00
@WEBjuju, ah yes, I meant to write about that, edited why it works. And yes, you had the quotes in the
iptables command so there it works fine.â ilkkachu
Feb 8 at 16:04
@WEBjuju, ah yes, I meant to write about that, edited why it works. And yes, you had the quotes in the
iptables command so there it works fine.â ilkkachu
Feb 8 at 16:04
@ilkkachu gotcha, yes, it seems silly on my end. somehow i knew it subconsciously but couldn't bring forth the knowledge to a working solution. i have somehow muddled through without knowing this basic tenant until now, but i just seriously leveled up. much thanks!
â WEBjuju
Feb 8 at 16:14
@ilkkachu gotcha, yes, it seems silly on my end. somehow i knew it subconsciously but couldn't bring forth the knowledge to a working solution. i have somehow muddled through without knowing this basic tenant until now, but i just seriously leveled up. much thanks!
â WEBjuju
Feb 8 at 16:14
add a comment |Â
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2funix.stackexchange.com%2fquestions%2f422842%2fbinary-operator-expected-quoting-question-for-shell-script-args%23new-answer', 'question_page');
);
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
1
If your goal in testing
$3is just to be sure that there are three parameters, then you can use the simpler$#shell variable, which holds the number of parameters, eg.if [ $# -ne 3 ].â user1404316
Feb 8 at 17:45
@user1404316 very useful - thanks
â WEBjuju
Feb 8 at 21:10