Hello please help me :)
#!/bin/bash
echo enter a number read n count=0 while[$n=!0] do count=$((count+1)) n=$((n/10)) done echo number of digits = $count This is my code for counting the number of digit in a number but it doesn't coz the terminal says enter a number 23 ./countdigits.sh: line 6: while[23=!0]: command not found ./countdigits.sh: line 7: syntax error near unexpected token `do' ./countdigits.sh: line 7: `do' I updated the software but the error is still there :( |
Welcome. You'll want to install the utility called shellcheck and use it often. There is also a web site of the same name which will also test shell scripts.
In the future, please wrap your scripts in [code] [/code] tags so that indentation is preserved. With all the formalities aside, compare, Code:
while[$n=!0] Code:
while [ $n != 0 ] |
#!/bin/bash
# Declare following two vars as integer declare -i n declare -i count echo Enter a Number: read n # the way I compare to integers (not using the posix method you are trying) # "-gt" for greater than # "-gte" for greater than or equal # "-ne" for not equal # "-lt" for less then # "-lte" for less than or equal # Also - note the spacing around the brackets below... don't try to save any spaces, it won't work. count=0 while [ $n -ne 0 ] do count=${count}+1 n=${n}/10 done echo number of digits = $count |
Quote:
Agreed, [ $n -ne 0 ] compares as numbers, and is straighter than [ $n != 0 ] that compares as strings (alphabetically). The spaces are required because [ is actually a command that wants a ] as last argument. (This is compatible with the old archaic Bourne shell. But also the modern [[ ]], not yet in the Posix standard, needs the spaces.) -- $(( )) enforces a numeric context and yields a value. While (( )) enforces a numeric context and does not yield a value, and is not yet in the Posix standard. Code:
#!/bin/bash |
Code:
read -p "Enter a number: " num |
Just goes to show that with linux there are lots of ways to do the same thing.
|
If you're going to use user supplied input in numeric context inside a (( )), [[ ]] or $(( )) then you need to validate it first as numeric context is unsafe and can lead to shenanigans!
Code:
$ read n && [[ n -gt 0 ]] && echo yes Code:
$ read n && (( n > 0 )) && echo yes The same is true for a declare -i n ; read n construct, except that there's no way to validate the input as it's already too late: Code:
$ declare -i n ; read n Code:
$ read n && [ "${n:-0}" -gt 0 ] && echo yes Moral of the story, always validate your inputs using a non-numeric context first. bash: Code:
read -p "Enter a number: " n || echo Code:
case $n in Now, if you're just writing scripts for yourself then you're not likely to try and exploit yourself, but it's wise to get into good habits. |
This kind of code injection wasn't on my radar, thanks for pointing it out!
One comment: to not allow an empty input it should be Code:
if [[ ! "$n" =~ ^[0-9]+$ ]]; then |
I decided to do a benchmark on the various ways I could come up with of validating the input using the output of seq 1 1000000.
Results Surprisingly, I found that "case" was the fastest and most efficient: Code:
$ cat /tmp/test-case Code:
$ cat /tmp/test-pattern_0-9 Next up, and perhaps not unsurprisingly, an extglob using the [:digit:] abstraction: Code:
$ cat /tmp/test-pattern_digit Now the difference start to get significant... Next up: a [ ] test using -ge 0 and -le 0 Code:
$ cat /tmp/test-gele Code:
$ cat /tmp/test-regex |
Quote:
Code:
$ type [ Code:
time while read n |
yes, regex is extremely slow in bash
Code:
[[ -n $n ]] || exit 1 |
Quote:
|
Quote:
Second one is a good idea though. Using sub is slightly slower than the extglob solutions: Code:
$ cat /tmp/test-sub |
Mind you... if you're concerned about performance, you're not going to be using bash anyway. :)
|
Quote:
Otherwise you can do a numeric check too, something like this: Code:
[[ $(( n + 2 )) -eq $(( n + 2 )) ]] || exit 1 |
All times are GMT -5. The time now is 07:44 PM. |