-1

I have a file named test.txt and it contains the following:

this is the last
char
another last
char
very last

I have a bash script (script.sh) having the following code:

#!/bin/bash

lastline=0
ctr=0

input="test.txt"
while IFS= read -r line
do
  ((ctr=ctr+1))
  echo "$ctr"
  if [ "$line" == "char" ]; then
      lastline=$ctr
  fi
done < "$input"

echo "$lastline"

My problem are these:

  1. When I run the command bash script.sh, I always get the value 0 for the variable lastline. It looks like it doesn't passed the condition even though there's a "char" on the test.txt file.

  2. It also seems like the while loop doesn't include the last line. There are 5 lines on the test.txt file, however, when I tried to echo out the variable ctr, the last number printed is only 4.

UPDATE

I've updated the code base on RavinderSingh13 answer. I added tr -d '\r' < test.txt > temp && mv temp test.txt

here's the updated code:

#!/bin/bash

tr -d '\r' < test.txt > temp && mv temp test.txt

lastline=1
ctr=1

input="test.txt"
while IFS= read -r line
do
  echo "$line"
  if [ "$line" == "char" ]; then
      lastline=$ctr
  fi
  ((ctr=ctr+1))
done < "$input"

echo "$lastline"

I definitely did see some weird characters (^M) at the end of each line when I ran the command cat -v test.txt, so I added RavinderSingh13 answer to remove them. However, it still doesn't retrieve the last line. If ever, the string on the last line is "char" then the result will be wrong. The picture below shows that the loop ends on the 4th line. The expected result should be 1 2 3 4 5 4. That's why if the "char" text is found on the last line, the result will be wrong since it didn't evaluated the last text on the last line.

enter image description here

  • Regarding #2, your text file probably doesn't follow POSIX conventions by ending with a newline character, so that call to `read` fails and the loop terminate early. – chepner Jan 05 '20 at 15:07
  • 1
    Also, if your file has DOS line endings, then the line you think is `char` is really `char\r`. Saving `test.txt` as a POSIX text file should solve both problems. – chepner Jan 05 '20 at 15:08
  • I run this script on this test file (yes, with unix line ending) and got sequence 1 2 3 4 5 4 as it should be. – ReAl Jan 05 '20 at 15:12
  • Unreproducible: https://ideone.com/Aj3gTY – tripleee Jan 05 '20 at 15:14
  • post the output of `od -c test.txt` so we can see the **entire** contents (including non-printable characters) of the file; when I execute your first code block I get `1 2 3 4 5 4`; when I execute your second code block I get all 5x lines printed to the console and then a line with `4` – markp-fuso Jan 05 '20 at 16:22
  • 1
    Duplicate of https://stackoverflow.com/questions/12916352/shell-script-read-missing-last-line – tripleee Jan 05 '20 at 16:24
  • hmmmm.. this is weird. Why am I the only one getting 1 2 3 4 4 – Lou KnowsAlready Jan 05 '20 at 16:58
  • using RavinderSingh13 awk code works perfectly fine though – Lou KnowsAlready Jan 05 '20 at 17:00
  • The DOS line ending issue is a duplicate of https://stackoverflow.com/questions/39527571/are-shell-scripts-sensitive-to-encoding-and-line-endings – tripleee Jan 05 '20 at 17:34
  • Because your file lacks the last newline, as indicated by the first duplicate nomination. Here is a demo which reproduces this: https://ideone.com/dd88ee – tripleee Jan 05 '20 at 17:37

1 Answers1

0

If you are ok with another solution, then you could try following. Which is efficient than shell solution.

awk '
$0=="char"{
  line=FNR
}
END{
  print "Last line number having string char is: " line
}
' Input_file

I am also checking your code and will post in few mins on same.



On OP's script: When I tested OP's script and ran it on my aws Ubuntu machine it runs fine as follows.

cat file.ksh
#!/bin/bash

lastline=0
ctr=0

input="test.txt"
while IFS= read -r line
do
  ((ctr=ctr+1))
###  echo "$ctr"
  if [ "$line" == "char" ]; then
      lastline=$ctr
  fi
done < "$input"

echo "$lastline"

./file.ksh
4

Suggestion to OP: Try to check if in case your Input_file named test.txt has Control M characters by doing cat -v test.txt if you see them then remove them by doing tr -d '\r' < test.txt > temp && mv temp test.txt

RavinderSingh13
  • 130,504
  • 14
  • 57
  • 93
  • Thank you Ravinder. I did see the control M characters when I run the command cat -v test.txt. I removed them using your code. However, the loop doesn't include the string/text on the last line. So if ever the text on the last line is "char", then the result will be wrong. – Lou KnowsAlready Jan 05 '20 at 16:19
  • @LouKnowsAlready, Sorry I don't understand why result will be wrong if string char is on last line? Once you remove Control M characters you could run either mine or your code to get the line number, kindly do try both codes and lemme know how it goes then? – RavinderSingh13 Jan 05 '20 at 16:24
  • the awk command works perferctly fine. I think I should use that. For the shell script, I don't know why but it skips the text of the last line. So for the sample file given above, the text "very last" is not evaluated on the loop, it is as if it stops always at the second to the last line. So if for example if "very last" is "char", then the result will still be 4 when the expected is 5. – Lou KnowsAlready Jan 05 '20 at 16:54
  • hmmmm.. this is weird. Why am i the only one doesn't get the last line of the loop. See attached image on my post. – Lou KnowsAlready Jan 05 '20 at 17:10