Shell Error while trying to perform a IF statement - shell

Good day.
I am trying to create a script to read each line of a specific file and then send each line to a second file depending on how many characters that line contains.
For example i have a file called numbers which contain the following information:
numbers.txt
5196803638
31995500317
5196396080
51999205240
5198158891
As you can see i have number with 8 or 9 numbers on each, i was trying to create a script that read a file line and send each number to its specific files.
!#/bin/bash
while IFS='' read -r line || [[ -n "$line" ]]; do
echo $line
if [ "${#line}"= 8 ]; then
$line> file8.txt
elif [ "${#line}"= 9 ]; then
$line> file9.txt
else
echo "Error"
fi
done < "$1"
But the only thing i get is the following
51996803638
My.sh: line 7: [: 11=: unary operator expected
My.sh: line 9: [: 11=: unary operator expected
Error

Your numbers have 10 or 11 characters. When you compare numerical values, use -eq, -ne, -lt, -gt, -le, -ge.
while IFS='' read -r line || [[ -n "$line" ]]; do
echo $line
echo "Length = ${#line}"
if [ ${#line} -eq 10 ]; then
echo $line >> file10.txt
elif [ ${#line} -eq 11 ]; then
echo $line >> file11.txt
else
echo "Error"
fi
done < "$1"

The shell's tokenizer is white-space sensitive. Use spaces around =, as in
if [ "${#line}" = 8 ]; then
$line> file8.txt
elif [ "${#line}" = 9 ]; then
$line> file9.txt
else
echo "Error"
fi
Or, what about this, which I find more readable/maintainable/extendable:
case ${#line} in
(8) $line > file8.txt;;
(9) $line > file9.txt;;
(*) echo Error;;
esac

Related

bash comparing variables that are integers with -gt -lt

I'm trying to make a bash script that reads integers from a file (one number per line, name of the file is passed as the script argument), finds maximum, minimum and sum. I've got a problem with the part, where I'm comparing variables, though. Code below (I've skipped here the part which checks whether the file exists or is empty):
#!/bin/bash
min=`cat "$1" | head -n 1`
max=$min
sum=0
lw=`cat "$1" | wc -l`
while [ $lw -gt 0 ];
do
num=`cat "$1" | tail -n $lw | head -n 1`
if [ "$num" -gt "$max" ]
then
max=$num
elif [ "$num" -lt "$min" ]
then
min=$num
fi
sum=$[sum+num]
lw=$[$lw-1]
done
echo "Maximum: $max"
echo "Minimum: $min"
echo "Sum: $sum"
With this code I'm getting errors in lines 13 and 16: [: : integer expression expected
If I change the comparision part inside the while loop to:
if [ $num -gt $max ]
then
max=$num
elif [ $num -lt $min ]
then
min=$num
fi
I'm getting errors:
line 13: [: -gt: unary operator expected
line 16: [: -lt: unary operator expected
What am I doing wrong? I'm a total newbie in bash, so I'll be extremely grateful for any help.
Data that I used for testing:
5
6
8
2
3
5
9
10
Probably your input file contains DOS line endings or other improper formatting. Your code should work for well-formed inputs.
However, the proper way to loop over the lines in a file is
#!/bin/bash
min=$(sed 1q "$1")
max=$min
sum=0
while read -r num; do
if [ "$num" -gt "$max" ]
then
max=$num
elif [ "$num" -lt "$min" ]
then
min=$num
fi
((sum+=num))
done<"$1"
echo "Maximum: $max"
echo "Minimum: $min"
echo "Sum: $sum"
Notice also that backticks and $[[...]]] use syntax which has been obselescent for decades already.
My guess would be that the expression
num=`cat "$1" | tail -n $lw | head -n 1`
assigns to num some value that is not a number in one of the iterations. I would suggest adding echo "$num" in the prev line to check this assumption
Another thing: instead of reading lines using cat | tail | head it is easier to read file line by line using the following syntax
while IFS= read -r line
do
echo "$line"
done < "$input"
This will read contents of input file into line variable.
See here for explanations about IFS= and -r https://www.cyberciti.biz/faq/unix-howto-read-line-by-line-from-file/ - both of them not really necessary in your case

[[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

Having difficulty writing a script to sort words

I am dealing with sorting words in Bash according to a given argument. I am given either argument -r, -a , -v or -h and according to it there are options to sort the words, as you can see at my "help".
Somehow, if I pass the argument -r it creates an error. I really don't understand what I am doing wrong, as if[["$arg"=="-a"]] works, but I have to use case somehow.
Here is my code:
#!/bin/bash
# Natalie Zubkova , zubkonat
# zubkonat#cvut.fel.cz , LS
#help
help="This script will calculate occurances of words in a given file, and it will sort them according to the given argument in following order> \n
without parametre = increasing order according to a number of occurance\n
-r = decreasing order according to a number of occurance\n
-a = in alphabetical increasing order\n
-a -r = in alphabetical decreasing order\n
There are also special cases of the given parametre, when the script is not sorting but:\n
-h = for obtaining help \n
-v = for obtaining a number of this task "
# this function will divide a given chain into a words, so we can start calculating the occurances, we also convert all the capital letters to the small ones by - tr
a=0;
r=0;
EXT=0;
if [ "$1" == "-h" ]; then
echo $help
exit 0
fi
if [ "$2" == "-h" ]; then
echo $help
exit 0
fi
if [ "$1" == "-v" ]; then
echo "5"
exit 0
fi
if [ "$2" == "-v" ]; then
echo "5"
exit 0
fi
function swap {
while read x y; do
echo "$y" "$x";
done
}
function clearAll {
sed -e 's/[^a-z]/\n/gI' | tr '[A-Z]' '[a-z]' | sort | uniq -c |awk '{i++; if(i!=1) print $2" "$1}' #swap
}
for arg do
case "$arg" in
"-a")
a=1
;;
"-r")
r=1
;;
"-v")
echo "5" #number of task is 5
exit 0
;;
"-h")
echo $help
exit 0
;;
"-?")
echo "invalid parametre, please display a help using argument h"
exit 0
;;
esac
done
#Sort according to parametres -a and -r
function sortWords {
if [[ a -eq 1 ]]; then
if [[ r -eq 0 ]]; then
clearAll | sort -nk1
fi
fi
if [[ a -eq 1 ]]; then
if [[ r -eq 1 ]]; then
clearAll | sort -nk1 -r
fi
fi
if [[ r -eq 1 ]]; then
if [[ a -eq 0 ]]; then
clearAll | sort -nk2 -r
fi
fi
if [[ a -eq 0 ]]; then
if [[ r -eq 0 ]]; then
clearAll | sort -nk2
fi
fi
}
#code is from Stackoverflow.com
function cat-all {
while IFS= read -r file
do
if [[ ! -z "$file" ]]; then
cat "$file"
fi
done
}
#histogram
hist=""
for arg do
if [[ ! -e "$arg" ]]; then
EXT=1;
echo "A FILE DOESNT EXIST" >&2
continue;
elif [[ ! -f "$arg" ]]; then
EXT=1;
echo "A FILE DOESNT EXIST" >&2
continue;
elif [[ ! -r "$arg" ]]; then
EXT=1;
echo "A FILE DOESNT EXIST" >&2
continue;
fi
done
for arg do
hist="$hist""$arg""\n"
done
echo -e "$hist" | cat-all | sortWords
exit $EXT;
Here is what our upload system which does some test to see if our program works says:
Test #6
> b5.sh -r ./easy.txt
ERROR: script output is wrong:
--- expected output
+++ script stdout
## --- line 1 (167 lines) ; +++ no lines ##
-the 89
-steam 46
-a 39
-of 37
-to 35
...
script written 484 lines, while 484 lines are expected
script error output:
A FILE DOESNT EXIST
cat: invalid option -- 'r'
Try `cat --help' for more information.
script exit value: 1
ERROR: Interrupted due to failed test
If anyone could help me I would really appreciate it.
You forgot to move the parameter index position with shift:
"-r")
r=1
shift
;;
shift above moves to the next command line arg: ./easy.txt in your case.
Without it, read -r file will read -r instead of the file name.

Bash print the number of incorrect file line

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.

if ["$i" -gt "$count"]; IS GIVING AN ERROR

I'm trying to put the 'f-$count'(f-1,f-2) name into the array.
Below is the code,
echo "Enter the count"
read count
echo $count
#arr=()
i=1
while true;
do
if ["$i" -gt "$count"]; then
exit 0
else
arr[$i]=f-$i
i=$((i+1))
fi
done
echo ${arr[#]}
I'm getting the error as 'script.sh: line 11: [3570: command not found
' continuously.
In shell programming, the brackets in the if MUST be delimited by spaces:
if ["$i" -gt "$count"]; then
MUST be:
if [ "$i" -gt "$count" ]; then
[EDIT] The left bracket ([) is actually a built-in shell command and so requires the space afterwards to delimit it from its parameters, as with any command.

Resources