Bash print the number of incorrect file line - bash

A beginner asking for help (:
So, I have a script that checks brackets in a text file and tells whether they are closed correctly. However, I also want to make my script print out the number of the incorrect line (where brackets are closed incorrectly). I have tried counting file lines and then making a nested while loop, however, it doesn't work for me at all ): Are there any simple solutions for this? I would like to leave the LINE counter if that's possible o:
INPUT="$1"
count=0
LINE=0
# Check if file exists
[ ! -f $INPUT ] && { echo "file $INPUT do not exist."; exit ; }
# Count file lines and read every char
while IFS= read -r LINE
do
LINE=$(( LINE + 1 ))
while read -n1 char
do
[ "$char" == "(" ] && (( count++ ))
[ "$char" == ")" ] && (( count-- ))
if [ "$count" -lt 0 ]
then
break
fi
done
done < "$INPUT"
if [ "$count" -lt 0 ]
then
echo "Found a mistake in $LINE line "
else
echo "Everything's correct"
fi

You have a couple of problems:
Your read in the inner loop consumes the input from the file, not from LINE.
The line
LINE=$(( LINE + 1 ))
is really wrong: LINE is the content of the line of your file, and your trying to add 1 to it. Weird.
Your break only breaks the inner loop (it should break two loops). Use break 2 for this.
Here's a working version of your script:
input=$1
count=0
linenb=0
# Check if file exists
[[ -f $input ]] || { echo "Error: file $input do not exist."; exit 1; }
# Count file lines and read every char
while IFS= read -r line; do
((++linenb))
while read -n1 char; do
[[ $char == '(' ]] && ((++count))
[[ $char == ')' ]] && ((--count))
((count>=0)) || break 2
done <<< "$line"
done < "$input"
if ((count<0)); then
echo "Found a mistake in line #$linenb:"
printf '%s\n' "$line"
else
echo "Everything's correct"
fi
Note that I used more ((...)) and [[...]].
I also used lowercase variable names, as your computer isn't deaf: you don't need to shout the name of the variable. (And it's nicer to the eye). And it's good practice to use lowercase variable names, as there's no chance that they clash with Bash's own variables.

Related

How to retain the value of a variable inside for loop in shell script

Below is my shell script code:
#!/bin/bash
first=0
my_for_loop()
{
first="$1";
if [ $first -eq 0 ]
then
return 1;
elif [ $first -eq 1 ]
then
return 0;
fi
}
while read line; do
for word in $line; do
echo "word = '$word'"; ( echo "$word" | grep -Eq "\([0-9]+\)" ) && ( word="${word%\)}"; word="`echo ${word} | cut -d'(' -f 2`"; echo "no = $word";
my_for_loop "$first"; first="$?"; echo "foo = $first")
done
echo "first value is $first" )
done
Basically I'm trying to read the words from the input and checking whether it is of the form "([0-9]+)" {e.g. (120) } if so, extracting the numerals i.e 120
The problem arises when I'm trying to set the variable "first" to 1 on the odd no of occurence of the pattern, and to 0 on eventh occurence
I tried Process Substitution, but not working porperly.
Can you help me with setting the boolean value inside the for loop such that it retains the value during next iteration also?
Avoid subprocesses. Is this want you want:
i=0
while read line ; do
cutted=$(sed 's/^(\([0-9]*\))$/\1/' <<< $line)
if [ "${line}" != "${cutted}" ]; then
(( i = !i))
echo "First=$i and ${cutted}"
fi
done
and use another loop when you cut things in words
i=0
while read line ; do
for word in $line; do
echo "${word}"
cutted=$(sed 's/^(\([0-9]*\))$/\1/' <<< ${word})
if [ "${word}" != "${cutted}" ]; then
(( i = !i))
echo "First=$i and ${cutted}"
fi
done
done

[[Bash]] Search for combined Expressions in every row

I am very new to Bash Scripting and I have a question regarding my CheckOurCodingRules.sh script:
I want to search for every 'hPar,' in a textfile and if found it should be checked if there is a also a 'const' in the same row.
Thats what I got so far but there is something wrong here:
while read line
do
if [[ $line == *hPar\,* ]] && [[ $line == *const\*]];then
DOCUMENTATION_TEST_A=1
else
echo DOCUMENTATION_TEST_A=0
fi
done < $INPUT_FILE
if [[DOCUMENTATION_TEST_A=0]];then
echo "error: Rule1: No const before hpar"
fi
There are a couple of issues with your script, see the code below which works for me:
DOCUMENTATION_TEST_A=0 # initial value
while read line
do
# spaces between conditional and brackets, no backslashes
if [[ $line == *hPar,* ]] && [[ $line == *const* ]]
then
DOCUMENTATION_TEST_A=1
break # optional, no need to scan the rest of the file
fi
done < $INPUT_FILE
# spaces and $, -eq is used for numerical comparisons
if [[ $DOCUMENTATION_TEST_A -eq 0 ]];
then
echo "error: Rule1: No const before hpar"
fi
A cleaner solution would be to use grep:
if ! grep "hPar," $INPUT_FILE | grep "const" >/dev/null
then
echo "error: Rule1: No const before hpar"
fi

Bash, reading a file line by line with jumps

I need to read a file line by line but sometimes, depends on condition, jump a number of lines.
How do I do that?
Thank you.
(sorry for my English)
#! /bin/bash
function skip() {
for (( i=0 ; i<$1; ++i )); do
read line
done
}
while read line; do
if [[ "$line" == "#"* ]]; then
skip 2
else
...
fi
done
while read line
do
echo "$line"
if [ "$line" != "As I expect" ]; then
echo "Jumping...";
fi
done

bash script gives directory listing as well when tokenizing

Here in the code below, line is a line of strings returned as the output of a command.
When I run the script, it gives me all the tokens of the string, but appends a listing of the directory to it as well. I really can't figure out what I am doing wrong.
for word in $line
do
inner_count=$((inner_count + 1))
echo $word
done
Here is the entire piece of code:
while read -r line
do
if [ "$count" = "2" ];
then
inner_count=0
#parse each line
#if [ "$debug" = "1" ] ; then printf "%s\n" "$line" > /dev/kmsg ; fi
for word in $line
do
if [ "$inner_count" = "0" ]; then tmp1="$word" ; fi
if [ "$inner_count" = "4" ]; then temp2="$word" ;fi
inner_count=$((inner_count + 1))
done
fi
count=$((count + 1))
done < <(batctl tg)
The most likely issue that I can think of that could produce this would be that there is a * in $line, and the shell is expanding that (globbing). You can disable globbing with set -f.
Try:
set -f # disable globbing
for word in $line
do
inner_count=$((inner_count + 1))
echo "$word"
done
set +f # re-enable globbing

bash: can read be used as a command or expression?

I want to make a oneliner loop that reads and checks what it read.
This surely won't work:
while [[ read line != "q" ]]; do; echo "enter q to quit: "; done
Zsh here tells me condition expected: read.
Perhaps read does not even have this concept of a return value.
Bash Pitfall #9:
if takes a command. [ is a command, not a syntax marker for the if statement. It's equivalent to the test command, except that the final argument must be a ].
[[ is not special syntax for the if condition. [[ is a command in its own right. Try a loop like this:
while read -r line; do
[[ $line = "q" ]] && break
# more code
done
read returns failure when it cannot read an expression, and [[ is a command, so this works. For more info see http://mywiki.wooledge.org/BashFAQ/001.
Note: Suuplying the -r switch to read is a good idea - it prevents funny things happening to backslashes in the input.
while read line; do; [[ "$line" == 'q' ]] && break; done;
seems to work.
But I'm not sure why I can't replace [[ ]] with [ ], it fails strangely:
$ bash
bash-3.2$ while true; do; read line; [ "$line" == 'q' ] && break; done;
bash: syntax error near unexpected token ';'
$ while true; do; read line; [ "$line" == 'q' ] && break; done;
ajlfkj
zsh: = not found

Resources