This question already has answers here:
Why should there be spaces around '[' and ']' in Bash?
(5 answers)
Closed 6 years ago.
OK i am sure this is an easy question but I am having trouble finding the answer. All I am trying to do is have an if statement that says if $stla is greater than -25 or $stla less than -16. I am pretty sure it is just a syntax thing but I am new to bash and havn't had much luck Googling the answer.
I attached my whole script, the variable assignment seems to be working, so you should need to worry about that. If I disable the if statement and just have echo $stlo it will print every $stlo, so I think the variables are correct.
Right now I just have if ["$stla" -lt "-25"] which returns "line 10: [33.63: command not found" So it is treating $stla as a command and not a number. How do I correct that? And once that is corrected how can I make a or condition to include greater than -25?
Sorry for the simple question, let me know if I need to clarify anything.
#!/bin/bash
for file in *.SAC; do
stla="$(saclst stla f $file)"
stla=(`echo $stla | awk '{print $2}'`)
stlo="$(saclst stlo f $file)"
stlo=(`echo $stlo | awk '{print $2}'`)
if ["$stla" -gt "-25"]
then
echo $stlo
fi
done
This works for me
stla=-24
if [[ "$stla" -gt "-25" ]]
then
echo $stla
fi
Please note spaces in if statement, and fixed a typo in echo $stla
If You want to you float:
stla=-24.5
if [[ $(echo "$stla > -25"| bc) -eq 1 ]]
then
echo $stla
fi
You can use printf and tr to enable fixed-point comparisons:
if [ $(printf "%0.2f" "$stla"|tr -d .) -gt -2500 ]
then
echo "$stlo"
fi
This works by first converting $stla into an integer. Effectively, it multiplies $stla by 100 by printing it with two decimal places and then stripping the decimal point. You manually multiply the other operand to make the comparison maintain its original meaning.
Related
The script found error but it always goes to Else condition "No Found Error". Am I missing how to compare two variables?
ERROR="Error:"
for i in `find /logs -mtime -1`
do
CHECK=`cat $i |grep -i "Error"|cut -f 1 -d " "`
if [ "$CHECK" == $ERROR ]
then
echo "Found Error"
else
echo "Not Found Error"
fi
done
Did you tried something like if [[ "$CHECK" == $ERROR ]] ?
To simply detect error without printing the error message, you can use
CHECK=$(cat $i | grep "Error" | wc -l)
if [[ $CHECK -ne 0 ]]
then
echo "Found error"
else
echo "Not found error"
fi
You are using grep -i for case-insensitive matching, but then testing the result for exact equality with the string Error:. If the case-insensitive matching is important then the exact equality test is not an appropriate complement.
You are also capturing a potentially multi-line output and comparing it to a string that can be the result only of a single-line output.
And you are matching "Error:" anywhere on the line, but assuming that it will appear at the beginning.
Overall, you are going about this a very convoluted way, as grep tells you via its exit status whether it found any matches. For example:
#!/bin/bash
for log in `find /logs -mtime -1`; do
if grep -i -q '^Error:' "$log"; then
echo "Found Error"
else
echo "Not Found Error"
fi
done
There is two things that I would advise and may fix your issue:
Add #!/bin/bash on the first line, to make sure it is interpreted as bash and not sh. Many time I had trouble with comparison because of this
When comparing two variables, uses double brackets ([[ and ]]) Also, if it strings, always put quotes "$ERROR" around it. It's missing for the $ERROR variable.
Look at the other answers also, there are many ways to do the same thing in a much simpler way.
Note: When comparing numbers you should use -eq
This question already has answers here:
Why should there be spaces around '[' and ']' in Bash?
(5 answers)
Closed 1 year ago.
I'm new to bash scripting and am having trouble trying to get this to work
local attempt=1
local success=false
while [[ "$attempt" -le "$retryAttempt" && "$success" -eq "false"]]; do
if ! [[ some condition here]];
then
echo true
return
fi
done
I'm getting an error on the while condition saying
line 10: [: missing ]
I cannot figure out what is wrong here, suggestions anyone?
Short: insert spaces around braces
Long: I wouldn't consider myself a bash pro (no idea what local is), but in a minimal syntax example (which is actually an infinity loop).
while [ $b -le $a] ; do
b=$a
done
gives me the same error. Changing the first line to
while [ $b -le $a ] ; do
works.
Depending on the complexity of the script, you might want to consider python or perl. In my opinion bash syntax can be a real pain in the a**. Especially when passing arguments with spaces through more than one level.
I've just started using Linux as part of my computer science degree.
I'm writing some very simple Bash scripts and I've become a tad bit stuck.
I would like the script I'm attempting to write to be able to differentiate between "non valid inputs ie letters" from "valid inputs ie numbers from a specific range"
Currently the script "works" although I'm having troubles with another echo that I would like only to "echo" when the below line is "not true", is there a simple way to write this? I'm not specifically looking for efficient code, just code that I can learn from and understand at my amateur level.
So, long story short, is it possible to obtain information from the command line below, so that I can have a simple "not true" variable that I can use in another "else" or "elif" command?
For reference line 1 is to detect alphabetical inputs, and line 2 being the line of code I would like to write as "not true" for use in another part of my script.
let xx=$a+1-1 2>/dev/null; ret=$?
if [ $a -ge 7 ] && [ $a -le 70 ] && [ $xx -eq $xx ] && [ $ret -eq 0 ]
I'm not sure I'm explaining it very well, so any help would be appreciated. :)
Welcome to Stack Overflow. :)
Start by reading the docs. I don't mean that in any way to be mean - it's just the best way to go about this.
c.f. this manual
Then read through the BashFAQs
Also, this site is really your friend. Start by familiarizing yourself with how to ask a question well.
For your question, if I read it right:
typeset -i xx # accepts only digits now.
If the input is foo, the value defaults to 0, so now just check the range.
if (( xx >= 7 && xx <= 70 )); then : value is ok
else echo "Value must be a number from 7 to 70"
exit 1
fi
Good luck. :)
One problem with the "variable with integer attribute" is that it still doesn't protect you from invalid input:
$ declare -i aNumber
$ aNumber=1234X
bash: 1234X: value too great for base (error token is "1234X")
See 6.5 Shell Arithmetic for how bash interprets values to be numbers (scroll down to the paragraph starting with "Integer constants follow the C language definition")
In my experience, the best way to check for valid numeric input is with string-oriented pattern matching.
if [[ $1 =~ ^[+-]?[0-9]+$ ]]; then
echo "input $1 is an integer"
fi
In addition to extended regular expressions, bash's advanced pattern matching can also be used within [[...]]
if [[ $1 == ?([+-])+([0-9]) ]]; then
echo "input $1 is an integer"
fi
((...)) is preferred over let. See the let builtin
command for details.
Also the shellcheck wiki entry.
This program is intended to read a file from stdin and return the longest and shortest lines. Right now it's in an infinite loop.Could someone tell me what I'm doing wrong?
Update: So after reading more about what read does, it's actually right (yay me) but I want to set the delimiter to a newline character while currently the read command is taking a string at every whitespace character. Does anyone know what I can do?
read T
short=""
long=""
for i in $T; do
if [[ $short = "" ]]; then
short=$i
elif [[ ${#i} -lt ${#short} ]]; then
short=$i
elif [[ ${#i} -gt ${#long} ]];then
long=$i
fi
done
echo $short
echo $long
It can't possibly reach an infinite loop, since you are looping over a
necessarily finite variable ($T).
I'm going to assume that your script is "hanging" and assume
one of the possible reasons (to provide you one possible
solution to your classroom problem): that the script is sleeping
waiting for data from stdin and no data is being sent to him.
Here's what you could do:
read short
long=$short
while read line; do
if [[ ${#line} -lt ${#short} ]]; then
short=$line
fi
if [[ ${#line} -gt ${#long} ]]; then
long=$line
fi
done
echo $short
echo $long
Notice that I've first initialized the short and long with the
first line of input, or empty string on stdin's EOF. Then I attempt
to read more lines in a while loop to then check for conditions to update short and
long; it is important to not exclude the line size checks if one
of them applies (like you didn't in your script using elifs).
I'm running into an issue where my argument list for echo is too long and would like some ideas on how to get around this issue, or at least test for the condition so I can properly handle it, and it won't kill my script
for file in `cat filelist`; do
PROTOCOLS1=`egrep -i 'rsh|rsync|remsh' "$file" | egrep -v '^[ | ]*#'`
FIELDS=`echo $PROTOCOLS1|wc -l`
if [[ $FIELDS -gt 1024 ]]; then
echo $file >> $debuglog
else
set -A myarray $PROTOCOLS1
do stuff.....
fi
done
So the problem is that when my arg list for echo is too long, $FIELDS is set to null, and thus my test for $FIELDS -gt 1024 always is true and does not get caught.
Problem is when it goes to the array it's obviously too big and I get a subscript out of range error and my script exits.
Any ideas are greatly appreciated.
Edit 9/18
OK so the problem is a little more basic.
myserver-v1> echo $variable
myserver-v1> /usr/bin/echo: too many args
I want to test for this in my script
I tried the following, which works, but I get all this crap to stdout, which fills up my debug log and is annoying
echo $variable
if [[ $? -ne 0 ]]; then
write to error log
fi
Is there a way to test echo $variable....without sending it to stdout?
I tried the following, but neither seemed to work, so I am kind of at a loss here.
[[ ! `echo $variable ]]
[[ `echo $variable ]]
If you keep the unquoted variable $PROTOCOLS1 in the echo, you could simplify life by replacing:
FIELDS=`echo $PROTOCOLS1|wc -l`
with
FIELDS=1
This is because when you echo $PROTOCOLS1 without any quotes around it, you will only have one (possibly very long) line of output. Alternatively, you can use:
FIELDS=$(echo "$PROTOCOLS1" | wc -l)
where the double quotes will preserve the newlines in the value of PROTOCOLS1 (but it gets you back to the 'argument list too long' problem).
So, you need to think about using:
FIELDS=$(egrep -i 'rsh|rsync|remsh' "$file" | egrep -c -v '^[ | ]*#')
which gets the second egrep to do the line counting for you. Obviously, since the later portion of the script uses $PROTOCOLS1, you will need to re-evaluate the egreps to get the data, but you should think about whether your processing scheme is appropriate. If you are running into a string value that is too long, you are probably not doing the processing in the best way. What the alternatives are depends on what you are trying to do, and the question does not reveal that. It might be appropriate to do the extra processing with a scripting language such as Perl, Python or Ruby.