Binary operator expected - quoting question for shell script args

The name of the pictureThe name of the pictureThe name of the pictureClash 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.







share|improve this question


















  • 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










  • @user1404316 very useful - thanks
    – WEBjuju
    Feb 8 at 21:10














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.







share|improve this question


















  • 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










  • @user1404316 very useful - thanks
    – WEBjuju
    Feb 8 at 21:10












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.







share|improve this question














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.









share|improve this question













share|improve this question




share|improve this question








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 $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












  • 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










  • @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










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.






share|improve this answer






















  • 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










  • @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











Your Answer







StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "106"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);

else
createEditor();

);

function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
convertImagesToLinks: false,
noModals: false,
showLowRepImageUploadWarning: true,
reputationToPostImages: null,
bindNavPrevention: true,
postfix: "",
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);



);








 

draft saved


draft discarded


















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






























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.






share|improve this answer






















  • 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










  • @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















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.






share|improve this answer






















  • 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










  • @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













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.






share|improve this answer














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.







share|improve this answer














share|improve this answer



share|improve this answer








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 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










  • @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

















  • 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










  • @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
















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













 

draft saved


draft discarded


























 


draft saved


draft discarded














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













































































Popular posts from this blog

How to check contact read email or not when send email to Individual?

Bahrain

Postfix configuration issue with fips on centos 7; mailgun relay