How can I test if line is empty in shell script? - bash

I have a shell script like this:
cat file | while read line
do
# run some commands using $line
done
Now I need to check if the line contains any non-whitespace character ([\n\t ]), and if not, skip it.
How can I do this?

Since read reads whitespace-delimited fields by default, a line containing only whitespace should result in the empty string being assigned to the variable, so you should be able to skip empty lines with just:
[ -z "$line" ] && continue

try this
while read line;
do
if [ "$line" != "" ]; then
# Do something here
fi
done < $SOURCE_FILE

bash:
if [[ ! $line =~ [^[:space:]] ]] ; then
continue
fi
And use done < file instead of cat file | while, unless you know why you'd use the latter.

cat i useless in this case if you are using while read loop. I am not sure if you meant you want to skip lines that is empty or if you want to skip lines that also contain at least a white space.
i=0
while read -r line
do
((i++)) # or $(echo $i+1|bc) with sh
case "$line" in
"") echo "blank line at line: $i ";;
*" "*) echo "line with blanks at $i";;
*[[:blank:]]*) echo "line with blanks at $i";;
esac
done <"file"

if ! grep -q '[^[:space:]]' ; then
continue
fi

blank=`tail -1 <file-location>`
if [ -z "$blank" ]
then
echo "end of the line is the blank line"
else
echo "their is something in last line"
fi

awk 'NF' file | while read line
do
# run some commands using $line
done
stole this answer to a similar question:
Delete empty lines using sed

Related

While read line with grep

I am trying to report lines found using grep and while.
I know you can use the following to compare a list of strings from inputs.txt and find them in your target file like so:
grep -f inputs.txt file_to_check
What I want is to read each line of the inputted strings and grep them individual in a loop.
So I have tried the following methods:
cat inputs.txt | while read line; do if grep "$line" filename_to_check; then echo "found"; else echo "not found"; fi; done
This returns nothing when I redirect the output to a file.
while read line
do
if grep "$line" file_to_check
then echo "found"
else
echo "not found"
fi
done < inputs.txt
Same as the first one but from what I found is better to do.
I know it iterates line by line because I can replace grep with echo $line and it prints each line; but either method doesn't return anything like grep -f above, instead it shows:
not found
not found
not found
.
. etc.
So what I'm looking for is something where it will iterate through each line and check it via grep using an if statement to determine if grep has actually found it or not. I know I may not have all proper logic but the output for what I want should look something like:
Found *matching line in file_to_check*
Found *matching line in file_to_check*
Not Found $line *(string that does not match)*
.
. etc.
You can also use && and || operators :
while read line; do
grep -q "$line" file_to_check && echo "$line found in file_to_check" || echo "$line not found in file_to_check"
done < inputfile > result.txt
The -q parameter of the grep just outputs a status code :
if $line is found, it outpouts 0 (True) the command after && will be evaluated
if not found, it outputs 1 (False) the command after || will evaluated
You can rewrite your final solution into
# Do not need this thanks to tr: file=$(dos2unix inputs.txt)
# Use -r so a line with backslashes will be showed like you want
while read -r line
do
# Not empty? Check with test -n
if [ -n "$(grep "${line}" filename)" ]; then
echo "found: ${line}"
else
echo "not found: ${line}"
fi
done < <(tr -d "\r" < "${file}")
Well, your if statement is pretty free form, you might need to clean it up a bit for bash to be able to read it. For example:
if [ "$(grep "$line" file_to_check)" != "" ]; then
echo "found: $line"
else
echo "not found: $line"
fi
This if statement will evaluate true if the grep command finds the line, because if it does it will spit the line out and will not be equal to "", or an empty string.
Here's my final solution:
file=$(dos2unix inputs.txt)
new_file=$file
while read line
do
if [ "$(grep "$line" filename)" != "" ]
then echo "found: $line"
else echo "not found: $line"
fi
done <$new_file
Thanks again!

How to break infinite loop in this script

I am doing something interesting with bash
I wrote script below:
#!/bin/bash
while :
do
if [ -s /tmp/file.txt ]; then
for line in $(cat /tmp/file.txt)
do
echo $line
#May be some commands here
done
fi
done
and the content of my file.txt is:
1 True
2 Flase
How can I say the script if command cat /tmp/file.txt is finished (I mean all lines are read) and also echo $line and other commands are finished then break the infinitive while : loop?
Thank you
Use break.
#!/bin/bash
while :
do
if [ -s /tmp/file.txt ]; then
for line in $(cat /tmp/file.txt)
do
echo $line
#May be some commands here
done
break
fi
done
Although it would be simpler and more proper with:
#!/bin/bash
for (( ;; )); do
if [[ -s /tmp/file.txt ]]; then
# Never use `for X in $()` when reading output/input. Using word splitting
# method for it could be a bad idea in many ways. One is it's dependent with
# IFS. Second is that glob patterns like '*' could be expanded and you'd
# produce filenames instead.
while read line; do
# Place variables between quotes or else it would be subject to Word
# Splitting and unexpected output format could be made.
echo "$line"
done < /tmp/file.txt
break
fi
done
On another note, do you really need the outer loop? This time you don't need to use break.
#!/bin/bash
if [[ -s /tmp/file.txt ]]; then
while read line; do
echo "$line"
done < /tmp/file.txt
fi

asterisk in ksh variable

abc.txt as
* This
Data1
Dat2
* Comment
data2
data3
When $line gets * as first char it does not work. It echoes garbage.
I tried various way but couldn't make it to work, how to check '*' in ksh varaible
while read line
do
fchar=`echo "$line" | cut -c 1-1`
#echo $fchar
if [[ ${char} = "*" ]]; then
continue
fi
if [[ ${char} = "#" ]]; then
continue
fi
echo ${line} >> stuff.txt
done<$abc.txt
Thanks.
Needs more quotes.
echo "$line" >>stuff.txt
...not
echo $line >>stuff.txt
...as the latter string-splits and glob-expands contents of the line, so it replaces * with a list of files in the current directory, replaces foo[bar] with foob if a file by that name exists, etc.
By the way, you'd be better off opening stuff.txt only once, not re-opening it every single time you want to add a new line. That'd look like this:
while read; do
fchar=${REPLY:0:1}
[[ "$fchar" = "*" ]] && continue
[[ "$fchar" = "#" ]] && continue
printf '%s\n' "$REPLY"
done >stuff.txt <abc.txt
By the way, you could also do this trivially with grep:
grep -E -v '^[*#]' <abc.txt >stuff.txt

how to search for blank lines in bash

I am trying to create an if statement that performs an action when it reads a blank line.
I would assume it would be something like this : if ($line=='\n');then
where line is the line that it is reading from a text file. But this is not working.
while read line; do
if [ "$line" = "" ]; then
echo BLANK
fi
done < filename.txt
or a slight variation:
while read line; do
if [ "$line" ]; then
echo NOT BLANK
else
echo BLANK
fi
done < filename.txt
try this:
if [[ "x$line" == "x" ]]; then...
or
if [[ "$line" =~ "^$" ]]; ...
Or also:
grep -q '.' <<< $line
Returns 1 if line is empty, 0 if non-empty

Splitting a line into words in bash

I would like to split a line into words. I know this can be done with this
For word in $line; do echo $word; done
But I want to make group of 3-3 words. So my question is, how can I split a line in group of 3-3 words ?
For example
Input : I am writing this line for testing the code.
Output :
I am writing
this line for
testing the code.
Read the words three at a time. Set the line being read from to the remainder:
while read -r remainder
do
while [[ -n $remainder ]]
do
read -r a b c remainder <<< "$remainder"
echo "$a $b $c"
done
done < inputfile
What about paste command
for word in $line; do echo $word; done | paste - - -
for word in $line; do echo $word; done | paste -d" " - - -
Easy regex exercise.
sed -e "s/\([^\ ]*\ [^\ ]*\ [^\ ]*\)\ /\1\\`echo -e '\n\r'`/g"
The only tricky part was getting the new line in the sed, as there isn't a standard for that.
$ echo "I am writing this line for testing the code."|sed -e "s/\([^\ ]*\ [^\ ]*\ [^\ ]*\)\ /\1\\`echo -e '\n\r'`/g"
I am writing
this line for
testing the code.
You're welcome.
Just use set to set your input as positional arguments, and process them in groups of three. That way you don't need anything fancy or bash-specific:
line="I am writing this line for testing the code."
set junk $line
shift
while [ $# -ge 3 ]; do
echo "Three words: $1 $2 $3"
shift 3
done
As a start you can use this, which reads every word into an array
#!/bin/bash
total=0
while read
do
for word in $REPLY
do
A[$total]=$word
total=$(($total+1))
done
done < input.txt
for i in "${A[#]}"
do
echo $i
done
Next step is to use seq or similar to loop through the array and print it in groups of three.
There's a non-generic straight forward solution:
#!/bin/bash
path_to_file=$1
while read line
do
counter=1;
for word in $line
do
echo -n $word" ";
if (($counter % 3 == 0))
then
echo "";
fi
let counter=counter+1;
done
done < ${path_to_file}
Save that in a script, give it a name (test.sh for example) and set it to execution mode. Than if your text is saved in "myfile.txt" call it like this:
test.sh myfile.txt
Here's an example of possible solution.
#!/bin/bash
line="I am writing this line for testing the code."
i=0
for word in $line; do
((++i))
if [[ $i -eq 3 ]]; then
i=0
echo "$word"
else
echo -ne "$word "
fi
done

Resources