how to compare strings by using the shell command of raspbian - linux

I found the relative instructions for normal linux versions are not suitable for raspbian, on RaspberryPi.
For example, the following command won't work,
$s1='bigger'
$s2='smaller'
if (($s1==$s2)); then
echo equal
else
echo unequal
fi
Any ideas from experienced programmers? Thanks!

That doesn't work for me either, on Debian. I'll answer assuming you're using #!/bin/bash (or similar constructs) as your shebang.
I get the following error:
./b: line 2: =bigger: command not found
./b: line 3: =smaller: command not found
./b: line 5: ((: ==: syntax error:
operand expected (error token is "==")
In general, $ should not be used on the left side of assignments. Let's get rid of those.
s1='bigger'
s2='smaller'
This does run, but not as we desire.
Running the modified script will output equal. This is because your double parenthesis ((x == y)) are performing an arithmetic equality operation, which isn't what you want.
To check for string equality in bash, do:
if [[ $s1 == "$s2" ]]; then
Here I've quoted the right hand side of the condition to prevent glob-matching.
The [[ construct is distinct from [ and is both more powerful and slightly less portable.
The final script then looks like:
#!/bin/bash
s1='bigger'
s2='smaller'
if [[ $s1 == "$s2" ]]; then
echo equal
else
echo unequal
fi
This does what we expect.

Related

Loop until choice within list

I am trying to write a script which loops until the user chooses a value within a list (single digit numbers from 0 to 9). This is my .sh script which I try to run in the ubuntu 16.04 shell using the sh command:
choice=999
echo $choice
until [[ $choice in 0 1 2 3 4 5 6 7 8 9 ]]
do
read -p "How many would you like to add? " choice
done
No matter what I do, I just can't get it to work. Here's a test, to give you an idea of the errors at hand:
sh test2.sh
999
test2.sh: 3: test2.sh: [[: not found
How many would you like to add? f
test2.sh: 3: test2.sh: [[: not found
How many would you like to add? 2
test2.sh: 3: test2.sh: [[: not found
How many would you like to add? 3
test2.sh: 3: test2.sh: [[: not found
How many would you like to add? r
test2.sh: 3: test2.sh: [[: not found
I've tried so many things:
Avoiding until and using while
Using just singular square brackets [ condition ], or no brackets at all
Using =~ to match the regular expression ^[0-9]
Nothing works. Always that same error. What's going on? :(
Firstly, your [[: not found suggests that you're not using Bash. Either add a #!/bin/bash at the top of your script, or run it with bash test2.sh, or use the standard [.
Either way, you can't use in like that. One alternative would be to use a case statement:
while :; do
read -p "How many would you like to add? " choice
case $choice in
[0-9])
break
;;
esac
done
The nice thing about case statements is that they allow you to use glob patterns, so [0-9] matches any number from 0 to 9.
If you are planning on using Bash in the end, you can also go for something like this:
#!/bin/bash
until [[ $choice =~ ^[0-9]$ ]]; do
read -p "How many would you like to add? " choice
done
Here, a regular expression is used to match a since digit from 0 to 9.
[[: not found is bash builtin, not sh.
Can you check your she-bang and be sure that it's #!/binb/bash, not #!/bin/sh ? And the second, run script as bash scriptname.sh, not with sh.
And finally, try to rewrite your script like that:
choice=999
echo $choice
while [[ "$(seq 0 9)" =~ "${choice}" ]]
do
read -p "How many would you like to add? " choice
# ((choice++)) If choice=999, script will not read anything.
# If 0 <= choice <= 9, script will not never stopped.
# So, you should uncomment ((choice++)) to stop script running when choice become
# more than 9.
done

What would cause the BASH error "[: too many arguments" after taking measures for special characters in strings?

I'm writing a simple script to check some repositories updates and, if needed, I'm making new packages from these updates to install new versions of those programs it refers to (in Arch Linux). So I made some testing before executing the real script.
The problem is that I'm getting the error [: excessive number of arguments (but I think the proper translation would be [: too many arguments) from this piece of code:
# Won't work despite the double quoted $r
if [ "$r" == *"irt"* ]; then
echo "TEST"
fi
The code is fixed by adding double square brackets which I did thanks to this SO answer made by #user568458:
# Makes the code works
if [[ "$r" == *"irt"* ]]; then
echo "TEST"
fi
Note that $r is defined by:
# Double quotes should fix it, right? Those special characters/multi-lines
r="$(ls)"
Also note that everything is inside a loop and the loop progress with success. The problems occurs every time the if comparison matches, not printing the "TEST" issued, jumping straight to the next iteration of the loop (no problem: no code exists after this if).
My question is: why would the error happens every time the string matches? By my understanding, the double quotes would suffice to fix it. Also, If I count on double square brackets to fix it, some shells won't recognize it (refers to the answer mentioned above). What's the alternative?
Shell scripting seems a whole new programming paradigm.. I never quite grasp the details and fail to secure a great source for that.
The single bracket is a shell builtin, as opposed to the double bracket which is a shell keyword. The difference is that a builtin behaves like a command: word splitting, file pattern matching, etc. occur when the shell parses the command. If you have files that match the pattern *irt*, say file1irt.txt and file2irt.txt, then when the shell parses the command
[ "$r" = *irt* ]
it expands $r, matches all files matching the pattern *irt*, and eventually sees the command:
[ expansion_of_r = file1irt.txt file2irt.txt ]
which yields an error. No quotes can fix that. In fact, the single bracket form can't handle pattern matching at all.
On the other hand, the double brackets are not handled like commands; Bash will not perform any word splitting nor file pattern matching, so it really sees
[[ "expansion_of_r" = *irt* ]]
In this case, the right hand side is a pattern, so Bash tests whether the left hand side matches that pattern.
For a portable alternative, you can use:
case "$r" in
(*irt*) echo "TEST" ;;
esac
But now you have a horrible anti-pattern here. You're doing:
r=$(ls)
if [[ "$r" = *irt* ]]; then
echo "TEST"
fi
What I understand is that you want to know whether there are files matching the pattern *irt* in the current directory. A portable possibility is:
for f in *irt*; do
if [ -e "$f" ]; then
echo "TEST"
break
fi
done
Since you're checking for files with a certain file name, I'd suggest to use find explicitly. Something like
r="$(find . -name '*irt*' 2> /dev/null)"
if [ ! -z "$r" ]; then
echo "found: $r"
fi

I am running into a No such file or directory error in bash, but it doesn't seem to be failing on a file

I have been running through my code for a while, and can't seem to find the reason this is failing because it is failing on line 10 apparently which is the if statement, but it is correctly finding the value of line.
#!/bin/bash
#a script that reads the largest number from a file
file="$1"
largest=""
while IFS= read -r line
do
if("$line" > "$largest")
then
"$largest"="$line"
fi
done <"$file"
echo "$largest"
This is incorrect:
if("$line" > "$largest")
then
"$largest"="$line"
fi
Change to:
if [ "$line" -gt "$largest" ]
then
largest="$line"
fi
First, as the pointed out in the comment, > is a redirection operator, and bash is trying to run the "$line" command. Parentheses are not test operators, the square brackets are.
Finally, the "$largest" is incorrect as the target of an assignment. The $ tells bash to provide the value of the variable, and we want to assign to largest, not to the VALUE of largest.

Bash script fails to recognise boolean logic, "command not found" [duplicate]

This question already has answers here:
How do I compare two string variables in an 'if' statement in Bash? [duplicate]
(12 answers)
Closed 6 years ago.
I'm new to Bash scripts, trying to make my first backup script. When I run it I always get something like this:
./backupscript.sh: line 9: [3=1: command not found
./backupscript.sh: line 9: 3=2]: command not found
./backupscript.sh: line 15: [3=1: command not found
./backupscript.sh: line 15: 3=3]: command not found
I have tried many different syntax, like ["var"="1"]||["var"=2], double brackets, without quotes, ()-brackets single and double and I'm losing my mind. It seems like bash isn't recognising at all that it's an if-statement. What's wrong? Thanks!
#!/bin/bash
cd /
NOW=$(date +"%m_%d_%Y")
echo "Please input: 1=full 2=system 3=home"
read choice
if ["$choice"="1" || "$choice"="2"]; then
echo "--- STARTING SYSTEMBACKUP ---"
tar -cvpzf systembackup_$NOW.tar.gz --exclude=/proc --exclude=/lost+found --exclude=/systembackup.tar.gz --exclude=/mnt --exclude=/sys --exclude=/dev --exclude=/run --exclude=/media --exclude=/home /
echo "--- SYSTEM BACKUP DONE ---"
fi
if ["$choice"="1" || "$choice"="3"]; then
echo "--- STARTING HOMEBACKUP (excluding ~/Seafile) ---"
tar -cvpzf homebackup_$NOW.tar.gz --exclude=/home/matias/Seafile /home
echo "--- HOMEBACKUP DONE ---"
fi
EDIT: Proper syntax suggested here did the trick, thanks everyone! I'm still looking for good guides on Bash :)
As #fedorqui said, you need spaces around the brackets. That is because [ is actually a synonym for test, a real program, and so is the name of an actual command.
To make your life easier in the future, use spaces and double brackets instead ([[ and ]]). Those are handled internally by bash and are more robust against accidental errors such as forgetting the quotes around a variable substitution. Plus, && and || work as logical AND and OR in double-brackets, but not in single brackets - you have to use -a and -o instead in [ ] expressions.
Using double-brackets ("conditional expressions" in bash), you can write:
if [[ $choice = 1 || $ choice = 3 ]]; then
...
fi
and get the result you expect.
Use the following as a best practice:
if [[ $choice == 1 || $choice == 2 ]]; then
...
fi
Notice the spaces and the == for equality test.
|| and && work in double brackets. Also has some other nice features, like REGEX matching with =~ along with operators like they are known in C-like languages along with less surprises.

bash double bracket issue

I'm very new to bash scripting and am running into an issue when using double brackets. I can't seem to get them to work at all in Ubuntu Server 11.10. My script below is in if_test.sh.
#!/bin/bash
if [[ "14"=="14" ]]; then
echo "FOO"
fi
When I run this simple shell script the output I get is: if_test.sh: 5: [[: not found
It seems that I'm running GNU bash version 4.2.10 after running bash --version from the terminal. Any help would be greatly appreciated. Thanks!
The problem lies in your script invocation. You're issuing:
$ sudo sh if_test.sh
On Ubuntu systems, /bin/sh is dash, not bash, and dash does not support the double bracket keyword (or didn't at the time of this posting, I haven't double-checked). You can solve your problem by explicitly invoking bash instead:
$ sudo bash if_test.sh
Alternatively, you can make your script executable and rely on the shebang line:
$ chmod +x if_test.sh
$ sudo ./if_test.sh
Also note that, when used between double square brackets, == is a pattern matching operator, not the equality operator. If you want to test for equality, you can either use -eq:
if [[ "14" -eq "14" ]]; then
echo "FOO"
fi
Or double parentheses:
if (( 14 == 14 )); then
echo "FOO"
fi
My answer doesn't apply to #lots_of_questions's question specifically, but you can also run into this problem if you have the wrong specifier at the top of your script:
#!/bin/sh
if [[ ... ]]
...
You should change that to
#!/bin/bash
if [[ ... ]]
...
Since you are new to scripting, you may be unaware that [[ is a bashism. You may not even know what a bashism is, but both answers given so far are leading you down a path towards a stunted scripting future by promoting their use.
To check if a variable matches a string in any flavor of Bourne shell, you can do test $V = 14 If you want to compare integers, use test $V -eq 14. The only difference is that the latter will generate an error if $V does not look like an integer. There are good reasons to quote the variable (test "$V" = 14), but the quotes are often unnecessary and I believe are the root cause of a common confusion, since "14"=="14" is identical to "14==14" where it is more obvious that '==' is not being used as an operator.
There are several things to note: use a single '=' instead of '==' because not all shells recognize '==', the [ command is identical to test but requires a final argument of ] and many sh coding guidelines recommend using test because it often generates more understandable code, [[ is only recognized by a limited number of shells (this is your primary problem, as your shell does not appear to recognize [[ and is looking for a command of that name. This is surprising if your shebang does indeed specify /bin/bash instead of /bin/sh).

Resources