I am new in shell script, trying to catch the return value of a program, and do something with it.
I have this script below
#!/bin/sh
if [ $# !=2 ] ; then
echo "Usage : param1 param2 "
exit 1;
elif [ $# -eq 2 ]; then
./callprogram
$out = $?
echo "$out"
fi
if [ $out==0 ]; then
echo "out ok"
fi
It keeps getting me error of
"[: 11: 0: unexpected operator
out ok
I have no clue why line 11 is wrong. if I remove "fi", it will promt that it needs "fi". Can anyone help with this matter?
Thank you
You need a space after the [ and you need to use -eq (equals) or -ne (not equals) to compare numbers in your if-statement.
To assign a variable use out=$?, not $out = $?. There should be no spaces on either side of the = sign.
Try this:
if [ $# -ne 2 ] ; then
echo "Usage : param1 param2 "
exit 1
elif [ $# -eq 2 ]; then
./callprogram
out=$?
echo "$out"
fi
if [ $out -eq 0 ]; then
echo "out ok"
fi
Change:
if [ $out==0 ]; then
to:
if [ $out = 0 ]; then
add spaces, and change '==' to '='. Note, that bash, executed as a bash accepts ==. But if you run is as a sh it will say "unexpected operator".
Why:
The [ is a command (or symlink to test binary, depending on your OS and shell). It expects $out and == and 0 and ] to be separate command arguments. If you miss the space around them, you have one argument $out==0.
BTW:
It's safer to always enquote the variables like that:
if [ "$var" ......
instead of
if [ $var
because when variable is empty, then you can get another error because of wrong number of arguments (no argument instead of empty string).
You have several problems. The one that is giving you the error is that you need a space after != on
if [ $# != 2 ]
(although -ne would be better than !=). It appears that you are calling the script with 11 arguments, and then calling [ with the arguments 11 !=2, and it does not know what to do with !=2 because you meant != 2 but forgot the space. Also, you want
out=$?
on the assignment (no $ on the LHS)
and
if [ $out = 0 ]
on the comparison. (Spaces around the operator, which is '=' instead of '=='. '==' will work on many shells, but '=' works in more shells.)
But your script would be better written without the explicit reference to $?
#!/bin/sh
if test $# != 2; then
echo "Usage: $0 param1 param2 " >&2 # Errors go to stderr, not stdout
exit 1;
fi
# you know $# is 2 here. No need to check
if ./callprogram; then
echo "out ok"
fi
Related
I need to check the existence of an input argument. I have the following script
if [ "$1" -gt "-1" ]
then echo hi
fi
I get
[: : integer expression expected
How do I check the input argument1 first to see if it exists?
It is:
if [ $# -eq 0 ]
then
echo "No arguments supplied"
fi
The $# variable will tell you the number of input arguments the script was passed.
Or you can check if an argument is an empty string or not like:
if [ -z "$1" ]
then
echo "No argument supplied"
fi
The -z switch will test if the expansion of "$1" is a null string or not. If it is a null string then the body is executed.
It is better to demonstrate this way
if [[ $# -eq 0 ]] ; then
echo 'some message'
exit 1
fi
You normally need to exit if you have too few arguments.
In some cases you need to check whether the user passed an argument to the script and if not, fall back to a default value. Like in the script below:
scale=${2:-1}
emulator #$1 -scale $scale
Here if the user hasn't passed scale as a 2nd parameter, I launch Android emulator with -scale 1 by default. ${varname:-word} is an expansion operator. There are other expansion operators as well:
${varname:=word} which sets the undefined varname instead of returning the word value;
${varname:?message} which either returns varname if it's defined and is not null or prints the message and aborts the script (like the first example);
${varname:+word} which returns word only if varname is defined and is not null; returns null otherwise.
Try:
#!/bin/bash
if [ "$#" -eq "0" ]
then
echo "No arguments supplied"
else
echo "Hello world"
fi
Only because there's a more base point to point out I'll add that you can simply test your string is null:
if [ "$1" ]; then
echo yes
else
echo no
fi
Likewise if you're expecting arg count just test your last:
if [ "$3" ]; then
echo has args correct or not
else
echo fixme
fi
and so on with any arg or var
Another way to detect if arguments were passed to the script:
((!$#)) && echo No arguments supplied!
Note that (( expr )) causes the expression to be evaluated as per rules of Shell Arithmetic.
In order to exit in the absence of any arguments, one can say:
((!$#)) && echo No arguments supplied! && exit 1
Another (analogous) way to say the above would be:
let $# || echo No arguments supplied
let $# || { echo No arguments supplied; exit 1; } # Exit if no arguments!
help let says:
let: let arg [arg ...]
Evaluate arithmetic expressions.
...
Exit Status:
If the last ARG evaluates to 0, let returns 1; let returns 0 otherwise.
I often use this snippet for simple scripts:
#!/bin/bash
if [ -z "$1" ]; then
echo -e "\nPlease call '$0 <argument>' to run this command!\n"
exit 1
fi
More modern
#!/usr/bin/env bash
if [[ $# -gt 0 ]]
then echo Arguments were provided.
else echo No arguments were provided.
fi
If you'd like to check if the argument exists, you can check if the # of arguments is greater than or equal to your target argument number.
The following script demonstrates how this works
test.sh
#!/usr/bin/env bash
if [ $# -ge 3 ]
then
echo script has at least 3 arguments
fi
produces the following output
$ ./test.sh
~
$ ./test.sh 1
~
$ ./test.sh 1 2
~
$ ./test.sh 1 2 3
script has at least 3 arguments
$ ./test.sh 1 2 3 4
script has at least 3 arguments
As a small reminder, the numeric test operators in Bash only work on integers (-eq, -lt, -ge, etc.)
I like to ensure my $vars are ints by
var=$(( var + 0 ))
before I test them, just to defend against the "[: integer arg required" error.
one liner bash function validation
myFunction() {
: ${1?"forgot to supply an argument"}
if [ "$1" -gt "-1" ]; then
echo hi
fi
}
add function name and usage
myFunction() {
: ${1?"forgot to supply an argument ${FUNCNAME[0]}() Usage: ${FUNCNAME[0]} some_integer"}
if [ "$1" -gt "-1" ]; then
echo hi
fi
}
add validation to check if integer
to add additional validation, for example to check to see if the argument passed is an integer, modify the validation one liner to call a validation function:
: ${1?"forgot to supply an argument ${FUNCNAME[0]}() Usage: ${FUNCNAME[0]} some_integer"} && validateIntegers $1 || die "Must supply an integer!"
then, construct a validation function that validates the argument, returning 0 on success, 1 on failure and a die function that aborts script on failure
validateIntegers() {
if ! [[ "$1" =~ ^[0-9]+$ ]]; then
return 1 # failure
fi
return 0 #success
}
die() { echo "$*" 1>&2 ; exit 1; }
Even simpler - just use set -u
set -u makes sure that every referenced variable is set when its used, so just set it and forget it
myFunction() {
set -u
if [ "$1" -gt "-1" ]; then
echo hi
fi
}
In my case (with 7 arguments) the only working solution is to check if the last argument exists:
if [[ "$7" == '' ]] ; then
echo "error"
exit
fi
I wrote a small korn script, but when I try to run the script, it will not echo the message I want to display. When I try to run it by
ksh script.sh -1
it is not echoing the message.
if [ $# -le 0 ]
then
echo "That is a negative integer!"
exit
fi
In bash/ksh $# represents the number of arguments passed as parameters.
What you needed is
if [ ${1:-0} -lt 0 ] # $1 is the first parameter
then
echo "That is a negative integer!"
exit
fi
Or a shorted version of the above
[ ${1:-0} -lt 0 ] && echo "That is a negative integer!" && exit
Edit 1
I have used shell [ parameter expansion ] ${1:-0} supply a default value.
Since zero is technically not a negative number, replace -le with -lt
Edit 2
If you're looking forward to match a particular string then do below
[ ${1:-NULL} = "StringToMatch" ] && DoSomething
If you're looking to see if the output is just has atleast one non-digit character,then do something like below
[[ {1:-NULL} =~ [^[:digit:]]+ ]] && DoSomething
Warning : Not all expansions mentioned in the link may not be supported by ksh
I have some problem with my code here. This is my code:
#!bin/sh
grep "$1" Rail.txt > test.txt
if [ "$#" -eq 1 -a grep -q "$1" test.txt ]; then
grep "$1" Rail.txt
else
echo not found
fi
Problem:
It says: script.sh: line 3: [: too many arguments every time I run it.
I'm not sure what's wrong with my condition whether I use the wrong operators or parenthesis or square brackets.
At a semi-educated guess, what you want to write is:
if [ "$#" -eq 1 ] && grep -q "$1" test.txt; then
On what ocassions should we use the square brackets?
Historically, the test command, /bin/test was linked to /bin/[, and was an external command, not a shell built-in. These days (and for several decades now), it has been a shell built-in. However, it follows the structure of a command, requiring spaces to separate arguments, and if it is invoked as [, then the last argument must be ].
As to when you use it, you use it when you need to test a condition.
Note that you can write:
if ls; false; true; then echo "the last command counts"; else echo "no it doesn't"; fi
The if command executes a sequence of one or more commands, and tests the exit status of the last command. If the exit status is 0, success, the then clause is executed; if the exit status is not 0, then the else clause is taken.
So, you can use the test when you need to test something. It can be part of an if or elif or while (or until). It can also be used on its own with || or &&:
[ -z "$1" ] && echo "No arguments - or the first argument is an empty string"
[ "$var1" -gt "$var2" ] || echo "Oops!" && exit 1
These could be written as if statements too, of course:
if [ -z "$1" ]
then echo "No arguments - or the first argument is an empty string"
fi
if [ "$var1" -le "$var2" ]
then
echo "Oops!"
exit 1
fi
Note that I needed to invert the test in the second rewrite. Bash has a built-in ! operator which inverts the exit status of the command that follows, so I could also have written:
if ! [ "$var1" -gt "$var2" ]
and test has a ! too, so it could also be written:
if [ ! "$var1" -gt "$var2" ]
I am having trouble to find the syntax error in the following script.
bash test.sh cat
#!/bin/bash
if [ $1 = "cat" ]; then
echo "valid"
else
echo "invalid"
fi
If you are not giving arguments, $1 will evaluate to a blank space and you are probably seeing line 2: [: =: unary operator expected. To fix, add quotes around $1:
#!/bin/bash
if [ "$1" = "cat" ]; then
echo "valid"
else
echo "invalid"
fi
This way, if you don't call with an argument it will still compare to an empty string.
In general, you should always put quotes around your variable expansions, otherwise you may see unexpected errors if the variable is empty (as you just saw) or if the variable has a space in it.
The arg $1 has no value. You could do something like this.
if [ -z $1 ]
then
echo "you forgot to give me an arg."
exit 1
fi
if [ $1 = "cat" ]; then
echo "valid"
else
echo "invalid"
fi
you can also do:
if [ $# -ne 1 ]; then
echo "Usage: ./script.sh <arg1>"
exit 1
fi
I need to check the existence of an input argument. I have the following script
if [ "$1" -gt "-1" ]
then echo hi
fi
I get
[: : integer expression expected
How do I check the input argument1 first to see if it exists?
It is:
if [ $# -eq 0 ]
then
echo "No arguments supplied"
fi
The $# variable will tell you the number of input arguments the script was passed.
Or you can check if an argument is an empty string or not like:
if [ -z "$1" ]
then
echo "No argument supplied"
fi
The -z switch will test if the expansion of "$1" is a null string or not. If it is a null string then the body is executed.
It is better to demonstrate this way
if [[ $# -eq 0 ]] ; then
echo 'some message'
exit 1
fi
You normally need to exit if you have too few arguments.
In some cases you need to check whether the user passed an argument to the script and if not, fall back to a default value. Like in the script below:
scale=${2:-1}
emulator #$1 -scale $scale
Here if the user hasn't passed scale as a 2nd parameter, I launch Android emulator with -scale 1 by default. ${varname:-word} is an expansion operator. There are other expansion operators as well:
${varname:=word} which sets the undefined varname instead of returning the word value;
${varname:?message} which either returns varname if it's defined and is not null or prints the message and aborts the script (like the first example);
${varname:+word} which returns word only if varname is defined and is not null; returns null otherwise.
Try:
#!/bin/bash
if [ "$#" -eq "0" ]
then
echo "No arguments supplied"
else
echo "Hello world"
fi
Only because there's a more base point to point out I'll add that you can simply test your string is null:
if [ "$1" ]; then
echo yes
else
echo no
fi
Likewise if you're expecting arg count just test your last:
if [ "$3" ]; then
echo has args correct or not
else
echo fixme
fi
and so on with any arg or var
Another way to detect if arguments were passed to the script:
((!$#)) && echo No arguments supplied!
Note that (( expr )) causes the expression to be evaluated as per rules of Shell Arithmetic.
In order to exit in the absence of any arguments, one can say:
((!$#)) && echo No arguments supplied! && exit 1
Another (analogous) way to say the above would be:
let $# || echo No arguments supplied
let $# || { echo No arguments supplied; exit 1; } # Exit if no arguments!
help let says:
let: let arg [arg ...]
Evaluate arithmetic expressions.
...
Exit Status:
If the last ARG evaluates to 0, let returns 1; let returns 0 otherwise.
I often use this snippet for simple scripts:
#!/bin/bash
if [ -z "$1" ]; then
echo -e "\nPlease call '$0 <argument>' to run this command!\n"
exit 1
fi
More modern
#!/usr/bin/env bash
if [[ $# -gt 0 ]]
then echo Arguments were provided.
else echo No arguments were provided.
fi
If you'd like to check if the argument exists, you can check if the # of arguments is greater than or equal to your target argument number.
The following script demonstrates how this works
test.sh
#!/usr/bin/env bash
if [ $# -ge 3 ]
then
echo script has at least 3 arguments
fi
produces the following output
$ ./test.sh
~
$ ./test.sh 1
~
$ ./test.sh 1 2
~
$ ./test.sh 1 2 3
script has at least 3 arguments
$ ./test.sh 1 2 3 4
script has at least 3 arguments
As a small reminder, the numeric test operators in Bash only work on integers (-eq, -lt, -ge, etc.)
I like to ensure my $vars are ints by
var=$(( var + 0 ))
before I test them, just to defend against the "[: integer arg required" error.
one liner bash function validation
myFunction() {
: ${1?"forgot to supply an argument"}
if [ "$1" -gt "-1" ]; then
echo hi
fi
}
add function name and usage
myFunction() {
: ${1?"forgot to supply an argument ${FUNCNAME[0]}() Usage: ${FUNCNAME[0]} some_integer"}
if [ "$1" -gt "-1" ]; then
echo hi
fi
}
add validation to check if integer
to add additional validation, for example to check to see if the argument passed is an integer, modify the validation one liner to call a validation function:
: ${1?"forgot to supply an argument ${FUNCNAME[0]}() Usage: ${FUNCNAME[0]} some_integer"} && validateIntegers $1 || die "Must supply an integer!"
then, construct a validation function that validates the argument, returning 0 on success, 1 on failure and a die function that aborts script on failure
validateIntegers() {
if ! [[ "$1" =~ ^[0-9]+$ ]]; then
return 1 # failure
fi
return 0 #success
}
die() { echo "$*" 1>&2 ; exit 1; }
Even simpler - just use set -u
set -u makes sure that every referenced variable is set when its used, so just set it and forget it
myFunction() {
set -u
if [ "$1" -gt "-1" ]; then
echo hi
fi
}
In my case (with 7 arguments) the only working solution is to check if the last argument exists:
if [[ "$7" == '' ]] ; then
echo "error"
exit
fi