elif [ "$arg" == "--file" ] || [ "$arg" == "-f" ] && [[ read var ]]
then
touch $var
I'm writing a bash script which takes in a command-line input, either long-form or short-form along with the file name to create an empty file with touch command. the above snippet is what I tried to do, but there's an error unary "read: unary operator expected".please help
This happens for most commands:
$ [[ echo "hello world" ]]
bash: conditional binary operator expected
bash: syntax error near `world"'
This is because [[ .. ]] should be used to compare values, and not to run commands. To run a command, don't wrap it in anything:
$ echo "hello world"
hello world
Applied to your example:
echo "You are expected to type in a value, but you will receive no prompt."
arg="-f"
if [ "$arg" == "--file" ] || [ "$arg" == "-f" ] && read var
then
echo "You entered: $var"
fi
Bash needs to know that it's running a whole command
To make bash aware that it's running a command you can use the backtick syntax (not recommended) or the preferred $() command substitution syntax. Without this syntax, bash is assuming that you're putting two separate strings inside of that condition.
The error you're getting is saying that you are trying to compare two strings without an operator to do so (i.e. -eq or ==).
Here is an example of how to make it recognize your commands:
elif [[ ... ]] && [[ $(read var) ]]
then
However, this won't work. This will evaluate to false. This is because you haven't printed anything out and as such an empty string ("") is falsey.
echo your variable to test its value
elif [[ ... ]] && [[ $(read var; echo $var) ]]
then
This will read into the variable and then test if the user has typed anything into it. If the user doesn't type anything, it will evaluate to false, otherwise, it will evaluate to true and run the body of the elif statement.
Related
This question already has answers here:
How to compare strings in Bash
(12 answers)
Closed 3 years ago.
I have a basic string equality check in a Bash script, but the output is not as expected.
To reproduce, copy the code below into an executable file (called 'deploy' in my examples below).
#!/bin/bash
echo $1
if [[ "$1" -eq "--help" ]] || [[ "$1" -eq "-h" ]]; then
echo "hello"
fi
If I run the script like so:
./deploy -h
The output is:
-h
hello
If I run the script like so:
./deploy --help
The output is:
-help
Why does the conditional statement not resolve to true?
-eq compares integers. Use == or = to compare strings.
if [[ "$1" == "--help" ]] || [[ "$1" == "-h" ]]; then
echo "hello"
fi
You could omit the quotes. Variable expansions on the left-hand side of == are safe when using double brackets.
You can also use || inside the brackets. It's not possible to do that with single brackets, but double brackets are a syntactical feature with special parsing rules that allow it.
if [[ $1 == --help || $1 == -h ]]; then
echo "hello"
fi
If it gets more complicated you might also consider a case block.
case $1 in
-h|--help)
echo "hello";;
esac
If -eq is for numerical comparison, how come ./deploy -h worked as expected?
Arithmetic evaluation normally prints an error message when given illegal expressions, but as it happens the two strings you're asking it to evaluate are syntactically valid.
-h negates the value of the undefined variable $h. The result is 0.
--help is decrements the undefined variable $help. The result is -1.
Try an invalid string and you'll get an error.
$ ./deploy 'foo bar'
bash: [[: foo bar: syntax error in expression (error token is "bar")
$ ./deploy #
bash: [[: #: syntax error in expression (error token is "#")
Say you have the user enter in a number 0-3 and want to test it. The most common way seems to be:
[[ $var =~ ^[0-3]$ ]]
But how would you use this with:
test expression
My initial attempt doesn't evaluate correctly, e.g.
read -p "Enter selection [0-3] > "
if test $REPLY == '^[0-3]$' ; then
...
It just evaluates the if statement as false.
test is equivalent to the [ ] structure, but not to [[ ]], which is an extended version. The regex =~ is only available in the extended test, so for simple test or [ ] you have to pull the regex evaluation from elsewhere.
One fix is grep. This pipeline will catch and print the matches:
echo "$REPLY" | grep '^[0-3]$'
Using test with a string evaluates positively if the string is non-empty. Compare these two:
test "" && echo ok
and
test "a" && echo ok
Knowing this, it's now easy to build a compound test from the both elements.
test "$(echo "$REPLY" | grep '^[0-3]$')"
And this can be applied to the script:
read -p "Enter selection [0-3] > "
if test "$(echo "$REPLY" | grep '^[0-3]$')"; then
...
fi
You can use a regex in Bash like this:
echo -n "Your answer> "
read REPLY
if [[ $REPLY =~ ^[0-9]+$ ]]; then
echo Numeric
else
echo Non-numeric
fi
Please check the post Using Bash's regular expressions.
I am trying to create an if statement using the test command that checks if the variable "name" contains "Scott Pearce".
#!/bin/bash
name="Scott Pearce"
if test $name == "Scott Pearce";
then
echo "Yes"
else
echo "No"
fi
When I run the script I get an error saying :
./script1: line 5: test: too many arguments
Any idea what I am doing wrong?
if test "$name" = "Scott Pearce";
You need to quote the variable, otherwise when the shell expands it, test will not get the right number of arguments since your variable contains a space.
Also the string equality operator for test is =, not ==.
If you really want to test contains, then pick one of
bash
if [[ $name == *"Scott Pearce"* ]]; then ...
POSIX
case "$name" in
*"Scott Pearce"*) echo Hi Scott ;;
*) echo Begone stranger ;;
esac
The == operator in bash's [[ command is a pattern matching operator.
What does the following bash syntax mean:
function use_library {
local name=$1
local enabled=1
[[ ,${LIBS_FROM_GIT}, =~ ,${name}, ]] && enabled=0
return $enabled
}
I don't particularly understand the line [[ ,${LIBS_FROM_GIT}, =~ ,${name}, ]]. Is it some kind of regex or string comparison?
This is a trick to compare variables and prevent a weird behaviour if some of them are not defined / are empty.
You can use , or any other. The main thing is that it wants to compare ${LIBS_FROM_GIT} with ${name} and prevent the case when one of them is empty.
As indicated by Etan Reisner in comments, [[ doesn't have empty variable expansion problems. So this trick is usually used when comparing with a single [:
This doesn't work:
$ [ $d == $f ] && echo "yes"
bash: [: a: unary operator expected
But it does if we add a string around both variables:
$ [ ,$d, == ,$f, ] && echo "yes"
$
Finally, note you can use directly this:
[[ ,${LIBS_FROM_GIT}, =~ ,${name}, ]] && return 0 || return 1
I want in a bash script (Linux) to check, if two files are identical.
I use the following code:
#!/bin/bash
…
…
differ=$(diff $FILENAME.out_ok $FILENAME.out)
echo "******************"
echo $differ
echo "******************"
if [ $differ=="" ]
then
echo "pass"
else
echo "Error ! different output"
echo $differ
fi
The problem:
the diff command return white space and break the if command
output
******************
82c82 < ---------------------- --- > ---------------------
******************
./test.sh: line 32: [: too many arguments
Error ! different output
The correct tool for checking whether two files are identical is cmp.
if cmp -s $FILENAME.out_ok $FILENAME.out
then : They are the same
else : They are different
fi
Or, in this context:
if cmp -s $FILENAME.out_ok $FILENAME.out
then
echo "pass"
else
echo "Error ! different output"
diff $FILENAME.out_ok $FILENAME.out
fi
If you want to use the diff program, then double quote your variable (and use spaces around the arguments to the [ command):
if [ -z "$differ" ]
then
echo "pass"
else
echo "Error ! different output"
echo "$differ"
fi
Note that you need to double quote the variable when you echo it to ensure that newlines etc are preserved in the output; if you don't, everything is mushed onto a single line.
Or use the [[ test:
if [[ "$differ" == "" ]]
then
echo "pass"
else
echo "Error ! different output"
echo "$differ"
fi
Here, the quotes are not strictly necessary around the variable in the condition, but old school shell scripters like me would put them there automatically and harmlessly. Roughly, if the variable might contain spaces and the spaces matter, it should be double quoted. I don't see a need to learn a special case for the [[ command when it works fine with double quotes too.
Instead of:
if [ $differ=="" ]
Use:
if [[ $differ == "" ]]
Better to use modern [[ and ]] instead of an external program /bin/[
Also use diff -b to compare 2 files while ignoring white spaces
#anubhava answer is correct,
you can also use
if [ "$differ" == "" ]