Loop until choice within list - linux

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

Related

how to compare strings by using the shell command of raspbian

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.

"if[ 0 -lt 1] command not found" error in shell script [duplicate]

This question already has answers here:
Why should there be spaces around '[' and ']' in Bash?
(5 answers)
Why is whitespace sometimes needed around metacharacters?
(5 answers)
Closed 5 years ago.
I got error message as if[ 0 -lt 1] command not found. I just started shell scripting. I don't know what's wrong in my code:
if[ $# -lt 1 ]
then
echo "Give a number as a parameter. Try again."
else
n=$1
sum= 0
sd=0
while[ $n -gt 0 ]
do
sd=`expr $n % 10`
sum=`expr $sum + $sd`
n=`expr $n / 10`
done
echo "Sum of digits for $1 is $sum"
You need a space between if and [. You'll have the same issue after while.
The [ ] notation is kind of an oddity in shell. It looks like part of the language, but it actually isn't. The if and while words always need to be followed by whitespace and then a command, which is executed, and considered to be true or false according to whether its exit code is zero or nonzero.
So there is actually a command named [ which evaluates the conditions given on its command line, and terminates with an exit code according to whether the condition evaluated true or false. You can see an executable in the /usr/bin directory on most systems (though the shell usually has a built-in version for efficiency). It works the same as test.
Also, keep in mind that if needs a matching fi after the else clause.
Check out https://www.shellcheck.net/ (Open Source - free)
It allows you to check your shell scripts before running them. You just copy your shell script into the browser and do a syntax check, you can also run locally.
Why?
Well, this I think will really help you learn what you are doing wrong.
i.e. Fix spacing errors etc.
Example Output:
$ shellcheck myscript
Line 1:
if[ $# -lt 1 ]
^-- SC1046: Couldn't find 'fi' for this 'if'.
^-- SC1073: Couldn't parse this if expression.
^-- SC1069: You need a space before the [.
Line 8:
while[ $n -gt 0 ]
^-- SC1069: You need a space before the [.
Line 15:
^-- SC1047: Expected 'fi' matching previously mentioned 'if'.
^-- SC1072: Expected 'fi'. Fix any mentioned problems and try again.
$

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.

Delete words from given files with sed

I have this assignment to solve:
"Write a shell script that continuously reads words from the keyboard and
deletes them from all the files given in the command line."
I've tried to solve it, here's my attempt:
#!/bin/bash
echo "Enter words"
while (true)
do
read wrd
if [ "$wrd" != "exit" ]
then
for i in $#
do
sed -i -e 's/$wrd//g' $i
done
else
break
fi
done
This is the error that I receive after introducing the command: ./h84a.sh fisier1.txt
Enter words
suc
sed: can't read 1: No such file or directory
Sorry if I'm not very specific, it's my first time posting in here. I'm working in a terminal on Linux Mint which is installed on another partition of my PC. Please help me with my problem. Thanks!
I think you can simplify your script quite a lot:
#!/bin/bash
echo "Enter words"
while read -r wrd
do
[ "$wrd" = exit ] && break
sed -i "s/$wrd//g" "$#"
done
Some key changes:
The double quotes around the sed command are essential, as shell variables are not expanded within single quotes
Instead of using a loop, it is possible to pass all of the file names to sed at once, using "$#"
read -r is almost always what you want to use
I would suggest that you take care with in-place editing using the -i switch. In some versions of sed, you can specify the suffix of a backup file like -i.bak, so the original file is not lost.
In case you're not familiar with the syntax [ "$wrd" = exit ] && break, it is functionally equivalent to:
if [ "$wrd" = exit ]
then break
fi
$# expands to the number of arguments (so 1 in this case)
You probably meant to use $* or "$#"

How do I control the user defined commands when executing a shell script in bash?

I am creating a shell script which has its own commands (or options). In simpler terms, my command line for executing the script is (in the terminal): ./myscript.sh -o:1,2,3,4 or ./myscript.sh -e:2,3,4. Here is what the code (for the option part) looks like so far:
myscript.sh
for i
do
case "$i" in
"-o:"*|"--only:"*)
# check if 1 is not included (if it is then exit)
;;
"-e:"*|"--except:"*)
# check if 1 is excluded (if it is then exit)
;;
*)
echo -e "invalid option\nTry './audit.sh --help' for help"
exit
;;
esac
done
Explanation:
The purpose of this code is to sum up all the values that the user passes through the ./myscript.sh -o:1,2,3,4 or subtract the values ./myscript.sh -e:2,3,4. The o is the "only" option which adds up only the numbers passed to the script from this option. The e is the "exclude" option which excludes the values the user defines and subtracts those from 100.
I have a restriction that the number 1 must always be there (whether adding or subtracting). So I can't exclude the number 1. Here are some examples of illegal user input commands (./myscript.sh -e:1,2,3,4) and (./myscript.sh -o:2,3,4).
How do i check if the number 1 is always included in the only option and that the number 1 is not excluded from the exclude option? Thanks.
EDIT: The method I want to approach is using awk. Any suggestions?
Get the value to check
Add commas to the front and end
Check of ,1, is a substring
Implementation:
i="--only:3,4,5"
value=${i#*:} # Strip prefix up to colon
if [[ ,$value, == *,1,* ]] # Check if ,1, is a substring
then
echo "You have a 1 in your list."
else
echo "You're missing 1"
exit 1
fi
To invert the check for checking exclusion, you can use !=.

Resources