[SOLVED] don't process last line in while loop - bash
Linux - NewbieThis Linux forum is for members that are new to Linux.
Just starting out and have a question?
If it is not in the man pages or the how-to's this is the place!
Notices
Welcome to LinuxQuestions.org, a friendly and active Linux Community.
You are currently viewing LQ as a guest. By joining our community you will have the ability to post topics, receive our newsletter, use the advanced search, subscribe to threads and access many other special features. Registration is quick, simple and absolutely free. Join our community today!
Note that registered members see fewer ads, and ContentLink is completely disabled once you log in.
If you have any problems with the registration process or your account login, please contact us. If you need to reset your password, click here.
Having a problem logging in? Please visit this page to clear all LQ-related cookies.
Get a virtual cloud desktop with the Linux distro that you want in less than five minutes with Shells! With over 10 pre-installed distros to choose from, the worry-free installation life is here! Whether you are a digital nomad or just looking for flexibility, Shells can put your Linux machine on the device that you want to use.
Exclusive for LQ members, get up to 45% off per month. Click here for more info.
This is a basic script from Advanced Bash Scripting which inserts a blank line after every 'paragraph' (which is defined as a minimum of 60 characters and which ends in *{\.}
Code:
#!/bin/bash
# paragraph-space.sh
# Ver. 2.1, Reldate 29Jul12 [fixup]
# Inserts a blank line between paragraphs of a single-spaced text file.
# Usage: $0 <FILENAME
MINLEN=60 # Change this value? It's a judgment call.
# Assume lines shorter than $MINLEN characters ending in a period
#+ terminate a paragraph. See exercises below.
while read line # For as many lines as the input file has ...
do
echo "$line" # Output the line itself.
len=${#line}
if [[ "$len" -lt "$MINLEN" && "$line" =~ [*{\.}]$ ]]
# if [[ "$len" -lt "$MINLEN" && "$line" =~ \[*\.\] ]]
# An update to Bash broke the previous version of this script. Ouch!
# Thank you, Halim Srama, for pointing this out and suggesting a fix.
then echo
fi
done
exit
# Add a blank line immediately
#+ after a short line terminated by a period.
One of the problems with this script is that it enters a blank line even at the end. So basically I need to stop the script from processing the last input line - I'm guessing. Any suggestions? I'd prefer if you didn't provide directly a solution, if that's possible, meaning, if it doesn't require a very specific trick that I wouldn't have been able to infer myself or something to that effect. Whatever
Basically the script will add a blank line if the length is less than 60 and contains a period at the end of the line regardless of where the line exists in the file.
One brute force method would be to determine the number of lines and use a for loop that is 1 less than max. That assumes there are always zero blank lines in the file after the last sentence. Realize this is only a simple example in the real world there could multiple exceptions.
Personally, after looking at the example, I am not sure the author knows regular expressions very well
Code:
[*{\.}]$
The problem is the above regex uses [] which disables the meaning of special characters, hence it actually says:
Match values ending in * or { or . or }, which is clearly not what we are looking for.
First tip for regex usage in bash is to assign the regex to a single quoted variable, where possible, and use it for the match.
So the pattern would be as simple as:
Code:
regex='\.$'
This can then be called in the match as follows:
Code:
[[ ... && "$line" =~ $regex ]]
You have 2 other issues with your code as presented:
Code:
then echo fi
done exit
Both of the above lines will force your code to not execute at all.
You either need the fi and exit on their own lines or a semi-colon after echo and done.
Other seem to have covered your issue of printing at the end
@grail. Yes, I know what you mean when you say that the script won't execute. There are problems when I copy/paste the text from the pdf which doesn't seem to be well formatted. I edited the post.
One problem I seem to have is that I cannot differentiate within the shell script between the name of the file and its content. If the script is invoked like this: $0 <filename, then the script/while loop only receives its content, one line at a time. So if I wanted to try michaelk's "bruteforce" solution, as he dubbed it, I wouldn't be able to invoke the filename (i'd need something like: wc -l filename | cut -d " " -f1) if I ran the script like that ($0 <filename).
So I guess a solution would be to use the filename as the first parameter ($1), instead of redirecting the filename's input. But the if I wrote while read $1, then the whole input of the file would be read, instead of taking it line by line. So how could I solve this first problem?
It's very daunting to see such an easy solution for a problem that I've been struggling to solve these couple of days. I hope it's just lack of experience, not the IQ
if read line
then
while read nextline
do
...
line=$nextline
done
printf "%s/n" "$line"
fi
I know this post is very old, but could you explain exactly what is going on here?
The script first reads each line (in the if statement), then while it reads (again?) each line - but this time we're using a different variable - assign the value of nextline to line. I really don't get that. What is actually happening?
The if read reads one line (the first line).
If successful, the while read reads the other lines.
The ...
can be code that deals with $line. And this $line is from the prevoius line.
I'm not sure how the second iteration of the while loop works. In the first iteration, line=$nextline means variable line is assigned the content of line 2.
Afterwards the loop starts over. So how come "nextline" in the second iteration becomes line 3? How does it actually know that? I mean, to my mind, it would have made sense if the variable 'nextline' was assigned something different.
I somehow dont' understand how the while loop takes into account a variable which is outside it, as it were. You update line to be $nextline, so does 'if read line' actually become 'if read «the content of nextline» and then the loop starts over? How can this be? I'm probably not making myself too clear, but I hope you understand. Don't hesitate to be as verbose as possible
start: if read line => line will contain the first line of the file
while read nextline => nextline will contain the second line
.... => you can process line (or even nextline) if you wish
line=$nextline => line will now contain the second line
done => will start the next loop
while read nextline => nextline will contain the next (currently third) line
.... => you can process [the previous] line (or even nextline) if you wish
line=$nextline => line will now contain the current line
done => will start the next loop
I think I made a basic mistake interpreting the script. line=$nextline has NOTHING to do with 'while read nextline', does it? Meaning, 'while read nextline' is always going to read the next line of the file on each iteration of the while loop regardless of the "line=$nextline" statement, right? line=$nextline is only useful in order to process the current line - echoing it, as it's in the initial version of the script.
I kept connecting two the statements and that didn't help too much. I hope I've got it right this time.
LinuxQuestions.org is looking for people interested in writing
Editorials, Articles, Reviews, and more. If you'd like to contribute
content, let us know.