I have a script to do research in my photo archive.
Beacause I've some files named with a merceological name before.
Since I want to avoid the problem that misspellings cause results to be lost. so I thought about this system.
Eg names files:
(Travel and Tourism) – titlea.jpg
(Travel and Tourism) – titleb.jpg
(Drinks) – titlea.jpg
I did this idea,
two researches, one precise with the exact name and the other extremely inaccurate with a few letters (consonants) that it is not possible for them to be missing (unless one does not type drunk). And that obviously are not all present together in other names.
If the subtraction is zero it means that the two results are the same and therefore without errors:
myfindTravelandTourism=$(find /PATH/ -type f -iname '*(Travel and Tourism)*' | wc -l)
StringVerifyTravelandTourism=$(find /PATH/ | cut -f1 -d '–' | grep
-i -F 'T' | grep -i -F 'R' | grep -i -F 'V' | wc -l)
if [ "${myfindTravelandTourism-StringVerifyTravelandTourism}" ≠ "0" ] ; then
echo "WARNING THE SCRIPT HAS DETECTED AN ORTOGRAPHICAL ERROR IN THE VIAGGI E TURISMO SECTOR!"
if [ {StringVerifyTravelandTourism} -ne ≠ "$0" ]; then
exit
fi
fi
But the error code bash:
[: ≠: integer expression expected.
I'm a beginner. This is my first conditional statement in bash
This ≠ is not an operator as a result it throws the error.
Also, to check for strings, you should use != instead of -ne. For example,
n1 -ne n2 To check whether numbers are algebraically equal or not.
s1 != s2 To check whether strings are not equal.
You can try the following code snippet:
if [[ $(( myfindTravelandTourism - StringVerifyTravelandTourism)) != 0 ]]; then
echo "not equal 0"
fi
Related
To give context to my issue. I am trying to move a list of files, where if the resolution is greater than 3.00, then move to a directory, Above3.
#!/bin/bash
files=`ls *.ent`
Above3=/mnt/d/Documents/Research/PhD/PhD/Research/Results/PDB/New/XRD/Above3
for f in $files; do
resolution=`cat $f | grep "REMARK 2 RESOLUTION." | awk '{print $4}' | tr -d ' '`
if [ $resolution -gt 3.00 ] ; then
mv $f $Above3
fi
done
The error I am getting is "integer expression expected" which I am not sure how to fix. Any suggestions on a solution will be greatly appreciated.
3.00 is a float value. Bash cannot process floating point values, only integers, hence the error message.
You could treat it as a string and compare it alphabetically if you can get your number in a fixed format (e.g. with two digits after the decimal point).
But I'd rather advise you use the command bc which is specifically made for calculations:
if [ $(bc <<< "$resolution > 3.00") == 1 ] ; then
mv $f $Above3
fi
What does the script (as a summary):
What does the script?
it takes all the files corresponding to *.ent in the current directory
it takes all the lines containing "REMARK 2 RESOLUTION." from all these files ; it takes the 4th word of these lines ; and puts the result into bash variable $resolution
if $resolution is greater than 3.00 it moves the corresponding file (one of the *.ent files) into the directory /mnt/d/Documents/Research/PhD/PhD/Research/Results/PDB/New/XRD/Above3
then it loops to proceed with the next file whose name matches *.ent
I am trying to execute a word count command on a log file and if the file has the "error" string, I want to take some action, but I can't seem to properly convert the grep to word count command to a real number so it compares properly to the greater than zero. So far with several variations, the conditional statement is always true.
if ((grep -Ei "error" myfile.log | wc -l)) > 0; then echo 1; else echo 0; fi
First of all, you can write conditions based on the exit code of programs.
If grep finds a matching line, it exits with success:
if grep -qEi "error" myfile.log; then echo 1; else echo 0; fi
I added the -q flag to not print the matching line, as you probably don't need it.
I strongly recommend to use the above solution, without wc.
But for the sake of completeness, here's some more explanation about different ways of comparing numbers.
One way to compare numbers is with -gt ("greater than") within [ ... ]:
if [ $(grep -Ei "error" myfile.log | wc -l) -gt 0 ]; then echo 1; else echo 0; fi
You can read about other operators within [ ... ] in help test.
Or using arithmetic context within ((...)):
if (($(grep -Ei "error" myfile.log | wc -l) > 0)); then echo 1; else echo 0; fi
Notice that in both of these examples I wrapped the grep ... | wc -l within a $(...) sub-shell to capture the output.
The syntax you wrote is incorrect.
Any way to combine these two IF statements into one...
if [ -n "$(system_profiler SPPrintersDataType | grep Shared | grep Yes)" ]; then
echo 1
fi
if [ -n "$(system_profiler SPPrintersDataType | grep 'System Printer Sharing: Yes')" ]; then
echo 1
fi
Add || short circuit evaluation in between:
if [ -n ... ] || [ -n ... ]; then ## Something; fi
|| is treated as logical OR (and && is logical AND).
In your case:
if [ -n "$(system_profiler SPPrintersDataType | grep Shared | grep Yes)" ] || [ -n "$(system_profiler SPPrintersDataType | grep 'System Printer Sharing: Yes')" ]; then
echo 1
fi
Just to note, if you use the bash keyword [[, then the following is valid too:
if [[ -n ... || -n ... ]]; then ## Something; fi
[[ -n $(system_profiler SPPrintersDataType | grep Shared | grep Yes)$(system_profiler SPPrintersDataType | grep 'System Printer Sharing: Yes') ]] && echo 1
Note:
You want to echo 1 if either one of the strings is non-empty or if the other one is non-empty. In this case, it is simpler to catenate the strings and look at the result: If the result is non-empty, at least one of the imput strings must be non-empty.
There is no need to use an if statement in this case (although it is not forbidden).
You don't need to quote the argument to -s, if you use [[ ... ]] for testing the string.
When you grep for Shared, should it be allowed that the word Yes appears before the word Shared in the line? If not, it would be simpler to write grep 'Shared.*Yes.
Since you are not interested in the actual output of the grep command, but only in the fact, that it matches, something like this would also work:
{system_profiler SPPrintersDataType|grep -q 'Shared.*Yes} || {system_profiler SPPrintersDataType|grep -Fq 'System Printer Sharing: Yes'} && echo 1
Finally, assuming that the system_profiler command produces the same output in both invocations, the code could be simplified to:
{system_profiler SPPrintersDataType|grep -Eq 'Shared.*Yes|System Printer Sharing: Yes'} && echo 1
This basically says: If there is a line in system_profiler which contains Shared...Yes OR a line containing System Printer Sharing Yes, then echo 1. You need the -E in inorder to get the | to work in the regexp pattern.
Admittedly, all these suggestions mean that you get only one 1 being echoed, if the condition is fulfilled, while in your original solution, you get two 1 being echoed, if both conditions are fulfilled. Therefore, my solution is not exactly equivalent to yours. However, since you explicitly said that you wanted to combine the cases, I think this is acceptable.
I don't know how the output of your system_profiler looks, so going a bit on guesswork here. If the Shared and Yes are always in the same order within a line, you can grep for them together with
grep 'Shared.*Yes'
and you can grep for both of your expressions in one pass with
grep 'Shared.*Yes\|System Printer Sharing: Yes'
You can then write your command as
system_profiler SPPrintersDataType \
| grep -q 'Shared.*Yes\|System Printer Sharing: Yes' \
&& echo 1
Note that we use grep -q to suppress output, as we're only interested in the return code.
Note also that if both of the strings are present, we only output one 1 - I'm guessing that's what you want, but I mention it as it is a difference from your script.
I'd like to understand bash a bit better as I'm apparently horrible at it...
I'm trying to generate a sequence of constant width integers, but then test them to do something exceptional for particular values. Like so:
for n in $(seq -w 1 150)
do
# The next line does not work: doit.sh: line 9: XX: command not found
#decval= $( echo ${n} | sed 's/^0//g' | sed 's/^0//g' )
#if [[ ${decal} -eq 98 ]] ; then
if [[ $( echo ${n} | sed 's/^0//g' | sed 's/^0//g' ) -eq 98 ]] ; then
echo "Do something different for 98"
elif [[ $( echo ${n} | sed 's/^0//g' | sed 's/^0//g' ) -eq 105 ]] ; then
echo "Do something different for 98"
fi
done
This script works for my purposes, but if I try and make the assignment 'decval= $(…' I get an error 'command not found'. I don't understand this, can someone explain?
Also, is there an improvement I can make to this script if I have a large number of exceptions to prevent a long list of if ; then elif … ?
The problem is in the space between = and $:
decval= $(…
You should write without spaces:
decval=$(...
Because, if you write the space, your shell reads decval= as declval="" and treats the result of $(echo...) as the name of a command to execute, and obviously it doesn't find the command.
Also (just a small optimization), you can write:
sed 's/^0\+//'
instead of
sed 's/^0//g' | sed 's/^0//g'
Here:
0\+ means 0 one or more times;
g is removed, because g means replace all occurences in the string, and you have only one occurence (^ can be only one time in a string).
Also, you can check your variable even with leading zeros, without sed:
[[ "$n" =~ "0*98" ]]
I have a question on the test command in the KornShell (ksh). I know -ne is for comparing integers and != is for comparing strings. How will the test command behave if one argument is a string and the other is an integer? I have below conditions in my code and both are working properly.
Code:
myCount=1
myCount=`expr $myCount+ 0`
temp=`ps -aef | grep damn | wc -l`
if [ $temp -ne $myCount]; then
echo ERROR Number
fi
if [ $temp != $myCount ]; then
echo ERROR Strings
fi
Output:
ERROR Number
ERROR Strings
The type is not relevant because it's a simple text substitution. In other words, the value of the variable $temp will be substituted in place of $temp (for example).
At least for the version of ksh I'm running, for the numeric comparison, if the value starts with a non-numeric, it will equate to 0. If it starts with a numeric but contains non-numerics, you will get an error.
For example:
$ export s1=xyz
$ export s2=7xyz
$ export i1=0
$ if [ $i1 -eq $s1 ]
> then
> echo equal
> fi
equal
$ if [ $i1 -eq $s2 ]
> then
> echo equal
> fi
ksh: 7xyz: bad number `7xyz'
However, based on your comments, that may not be the case for all versions of ksh.
Based on that, I would try to ensure that you use string comparisons for strings and numeric comparisons for numbers. Anything else may be non-portable.
But your code is flawed anyway.
temp=ps -aef | grep damn | wc -l
will always return at least 1, since it will find the grep command as well as being a string padded with leading spaces, which is why both of your tests are true.
Piping to wc is also unnecessary since the -c switch of grep will count for you.
better code would be:
temp=ps -aef |grep damn |grep -cv grep
which will return the number of running instances of processes containing the damn string and it will be a number.
Using ksh93 and GNU coreutils expr 7.4 your command:
myCount=`expr $myCount+ 0`
gives me a syntax error and sets myCount to null which causes both if statements to output "ksh: [: argument expected" errors. Try putting a space before the plus sign. Also, there needs to be a space before ].
You shouldn't need to convert myCount or temp to integers. The coercion of myCount using expr is completely unnecessary.
I prefer this form for comparing integers since it allows you to use symbolic comparison operators such as != and > instead of -ne and -gt:
if (( $temp != $myCount ))