I would like to have a bash script that checks if a file has more than # amount of lines but i have not yet got it working right and I'm not so sure on how to do it.
I've never used bash before.
right now i use: linesStr=$(cat log | wc -l) to get the amount of lines in the file (expect it to be a string). when echo'ing it gives me the number 30 which is correct.
but since its most likely a string it doesnt do the if-statement, so i need to have linesStr converted into a int called linesInt.
I also have the feeling the if-statement itself is not done correctly either.
#!/bin/bash
linesStr=$(cat log | wc -l)
echo $linesStr
if [$linesStr > 29]
then echo "log file is bigger than 29 lines"
#sed -i 1d log
fi
I would appreciate if anyone can give me a simple beginners solution.
No need for cat.
Lack of spaces around [ and ].
Use a numeric comparison operator instead of the redirect operator.
Here is a working script.
#!/bin/bash
linesStr=$( wc -l < log )
if [[ "$linesStr" -gt "29" ]]; then
echo Foo
fi
your if block of code is wrong if [$linesStr > 29] there should be a space after [ and before ]
#!/bin/bash
linesStr=$(wc -l < log )
echo $linesStr
if [[ $lineStr -gt 29 ]];then
echo "log file is bigger than 29 lines"
fi
it is advisable that you always use [[ ]] with an if statement rather than using [ ]. Whenever you want to compare integers dont use > or <, use -gt -ge -lt -le. And if you want to do any form of mathematical comparison it is advisable that you use (( )).
(( lineStr > 29 )) && {
# do stuff
}
you should also note that you don't need the bash comparison operators or getting the value of a variable with $ when using (( ))
There are no string or integer types to convert. The problem is that you're using the wrong comparison operator. For numeric comparison use if [ $linesStr -gt 29 ]. Read man bash section CONDITIONAL EXPRESSIONS for available operators.
(( $(wc -l < log) > 29 )) && echo too long
Related
I use bash, I have to read a file that contains many lines
Each line is composed by a single number. Then, for each line (number) I have to check if value > 80.
And here's my problem, no matter what I try, I always get:
>integer expression expected
after the if condition. That's because the variable I use to put the value of the line is a string.
Here's my original file
[root#michelep_centos2 ~]# cat temp1
0
0
0
98
0
0
79
0
81
In the bash script I have
##!/bin/bash
file=/root/temp1
while IFS= read -r line
do
if [ 'expr $line /1' -gt 80 ]
then echo "hit>80"
fi
done <"$file"
And here expr returns error as $line is a string. I have tried using another variable
val=$(($line + 0))
if [ $val -gt 80 ]
Here the if condition returns "integer expression expected"
I have used also echo
val=$(echo "$((line /1))")
if [ $val -gt 80 ]
I get
syntax error: invalid arithmetic operator (error token is ...
from echo command and of course again the if condition returns
integer expression expected
First action: dos2unix -f inputfile
Second action:
From the input file it can be observed that it contains blank lines, and this will cause if comparison to fail. You can put an additional check on top of your -gt 80 check to ensure before passing the variable $line its not empty using if [ ! -z $line ] or better you can put a check to ensure the line is an integer or may be both using AND.
Example:
while read line;
do
if [[ $line =~ ^[0-9]+$ ]];then
if [ $line -gt 80 ];then
echo "$line is greater then 80"
fi
fi
done <input_file
Or , if you do not want to put empty check([ ! -z $line ]) ,
Also, this can be done using other tools like awk in one line, but this may or may not fit in your requirement.
awk 'NF && $0>80{print $0 ,"is greater then 80"}' inputfile
Try this Shellcheck-clean pure Bash code:
#! /bin/bash -p
file=/root/temp1
while read -r line ; do
(( line > 80 )) && echo "$line > 80"
done <"$file"
The problem with the code in the question is that it doesn't handle empty lines. This code does handle empty lines because variables containing the empty string are treated as if they contained zero in arithmetic expressions (((...))).
Hello everybody and sorry for bad English!
I'm trying to make a "telegram alert" and made this conditional:
NOW=$(date +%s)
NOWCHECK=$((NOW-3))
[...]
if ("$DATE" < "$NOWCHECK"); then # DATE is a string variable with seconds passed from 1/1/1970
...
fi
I get this error:
line 26: 1458939588: No such file or directory
What am I doing wrong?
Thanks in advance!
What you're experiencing is Bash is trying to execute the expression within (...). It's interpreted as running the $DATE command, and redirecting input to it from $NOWCHECK. But that's not what you want.
The operator for arithmetic operations is ((...)) not (...). Do like this:
if (("$DATE" < "$NOWCHECK")); then
And it would be better to drop the $ inside the ((...)):
if ((DATE < NOWCHECK)); then
Use:
if [[ "$DATE" -lt "$NOWCHECK" ]]; # -lt: less than
If you have this two variables set:
NOW=$(date +%s) NOWCHECK=$((NOW-3))
Then: Either switch to correct Arithmetic Expansion (( ... ))
if (( NOW < NOWCHECK )); then
...
fi
Or remove the < character (which is interpreted as a redirection and presents an error as the source file named as the value of NOWCHECK does not exist):
if [[ $NOW -lt $NOWCHECK ]]; then
...
fi
if [ "$NOW" -lt "$NOWCHECK" ]; then
...
fi
My Syst admin prof just started teaching us bash and he wanted us to write a bash script using grep to find all 3-45 letter palindromes in the linux dictionary without using reverse. And im getting an error on my if statement saying im missing a '
UPDATED CODE:
front='\([a-z]\)'
front_s='\([a-z]\)'
numcheck=1
back='\1'
middle='[a-z]'
count=3
while [ $count -ne "45" ]; do
if [[ $(($count % 2)) == 0 ]]
then
front=$front$front_s
back=+"\\$numcheck$back"
grep "^$front$back$" /usr/share/dict/words
count=$((count+1))
else
grep "^$front$middle$back$" /usr/share/dict/words
numcheck=$((numcheck+1))
count=$((count+1))
fi
done
You have four obvious problems here:
First about a misplaced and unescaped backslash:
back="\\$numcheck$back" # and not back="$numcheck\$back"
Second is that you only want to increment numcheck if count is odd.
Third: in the line
front=$front$front
you're doubling the number of patterns in front! hey, that yields an exponential growth, hence the explosion Argument list too long. To fix this: add a variable, say, front_step:
front_step='\([a-z]\)'
front=$front_step
and when you increment front:
front=$front$front_step
With these fixed, you should be good!
The fourth flaw is that grep's back-references may only have one digit: from man grep:
Back References and Subexpressions
The back-reference \n, where n is a single digit, matches the substring
previously matched by the nth parenthesized subexpression of the
regular expression.
In your approach, we'll need up to 22 back-references. That's too much for grep. I doubt there are any such long palindromes, though.
Also, you're grepping the file 43 times… that's a bit too much.
Try this:
#!/bin/bash
for w in `grep -E "^[[:alnum:]]{3,45}$" /usr/share/dict/words`; do if [[ "$w" == "`echo $w|sed "s/\(.\)/\1\n/g"|tac|tr -d '\012'`" ]]; then echo "$w == is a palindrome"; fi; done
OR
#!/bin/bash
front='\([a-z]\)'
numcheck=1
back='\1'
middle='[a-z]'
count=3
while [ $count -ne "45" ]; do
if [[ $(($count % 2)) == 0 ]]
then
front=$front$front
back="\\$numcheck$back"
grep "^$front$back$" /usr/share/dict/words
else
grep "^$front$middle$back$" /usr/share/dict/words
## Thanks to gniourf for catching this.
numcheck=$((numcheck+1))
fi
count=$((count+1))
## Uncomment the following if you want to see one by one and run script using bash -x filename.sh
#echo Press any key to continue: ; read toratora;
done
I wrote a bash script that performs a curl call only during business hours. For some reason, the hourly comparison fails when I add an "-a" operator (and for some reason my bash does not recognize "&&").
Though the script is much larger, here is the relevant piece:
HOUR=`date +%k`
if [ $HOUR > 7 -a $HOUR < 17 ];
then
//do sync
fi
The script gives me the error:
./tracksync: (last line): Cannot open (line number): No such file
However, this comparison does not fail:
if [ $DAY != "SUNDAY" -a $HOUR > 7 ];
then
//do sync
fi
Is my syntax wrong or is this a problem with my bash?
You cannot use < and > in bash scripts as such. Use -lt and -gt for that:
if [ $HOUR -gt 7 -a $HOUR -lt 17 ]
< and > are used by the shell to perform redirection of stdin or stdout.
The comparison that you say is working is actually creating a file named 7 in the current directory.
As for &&, that also has a special meaning for the shell and is used for creating an "AND list" of commands.
The best documentation for all these: man bash (and man test for details on comparison operators)
There are a few answers here but none of them recommend actual numerical context.
Here is how to do it in bash:
if (( hour > 7 && hour < 17 )); then
...
fi
Note that "$" is not needed to expand variables in numerical context.
I suggest you use quotes around variable references and "standard" operators:
if [ "$HOUR" -gt 7 -a "$HOUR" -lt 17 ]; ...; fi
Try using [[ instead, because it is safer and has more features. Also use -gt and -lt for numeric comparison.
if [[ $HOUR -gt 7 && $HOUR -lt 17 ]]
then
# do something
fi
I am looking for a command (or way of doing) the following:
echo -n 6 | doif -criteria "isgreaterthan 4" -command 'do some stuff'
The echo part would obviously come from a more complicated string of bash commands. Essentially I am taking a piece of text from each line of a file and if it appears in another set of files more than x (say 100) then it will be appended to another file.
Is there a way to perform such trickery with awk somehow? Or is there another command.. I'm hoping that there is some sort of xargs style command to do this in the sense that the -I% portion would be the value with which to check the criteria and whatever follows would be the command to execute.
Thanks for thy insight.
It's possible, though I don't see the reason why you would do that...
function doif
{
read val1
op=$1
val2="$2"
shift 2
if [ $val1 $op "$val2" ]; then
"$#"
fi
}
echo -n 6 | doif -gt 3 ls /
if test 6 -gt 4; then
# do some stuff
fi
or
if test $( echo 6 ) -gt 4; then : ;fi
or
output=$( some cmds that generate text)
# this will be an error if $output is ill-formed
if test "$output" -gt 4; then : ; fi