LinuxQuestions.org
Latest LQ Deal: Latest LQ Deals
Home Forums Tutorials Articles Register
Go Back   LinuxQuestions.org > Forums > Linux Forums > Linux - Newbie
User Name
Password
Linux - Newbie This 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


Reply
  Search this Thread
Old 08-18-2017, 11:44 AM   #1
vincix
Senior Member
 
Registered: Feb 2011
Distribution: Ubuntu, Centos
Posts: 1,240

Rep: Reputation: 103Reputation: 103
don't process last line in while loop - bash


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

Last edited by vincix; 08-20-2017 at 09:51 AM.
 
Old 08-18-2017, 11:55 AM   #2
pan64
LQ Addict
 
Registered: Mar 2012
Location: Hungary
Distribution: debian/ubuntu/suse ...
Posts: 21,836

Rep: Reputation: 7308Reputation: 7308Reputation: 7308Reputation: 7308Reputation: 7308Reputation: 7308Reputation: 7308Reputation: 7308Reputation: 7308Reputation: 7308Reputation: 7308
if [[ "$len" -lt "$MINLEN" && "$line" =~ [*{\.}]$ ]]
checks maximal length, not minimal.

From the other hand you may insert set -xv at the beginning of your script to see what's happening.
 
1 members found this post helpful.
Old 08-18-2017, 12:21 PM   #3
michaelk
Moderator
 
Registered: Aug 2002
Posts: 25,699

Rep: Reputation: 5895Reputation: 5895Reputation: 5895Reputation: 5895Reputation: 5895Reputation: 5895Reputation: 5895Reputation: 5895Reputation: 5895Reputation: 5895Reputation: 5895
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.
 
Old 08-18-2017, 01:05 PM   #4
rknichols
Senior Member
 
Registered: Aug 2009
Distribution: Rocky Linux
Posts: 4,777

Rep: Reputation: 2212Reputation: 2212Reputation: 2212Reputation: 2212Reputation: 2212Reputation: 2212Reputation: 2212Reputation: 2212Reputation: 2212Reputation: 2212Reputation: 2212
Set a flag at the bottom of the loop. At the top of the loop, if the flag is set, echo a blank line and clear the flag.
Code:
Flag=0
while read Line
do  ((Flag-- > 0)) && echo
    .
    .
    .
    Flag=1
done
 
Old 08-19-2017, 05:53 AM   #5
grail
LQ Guru
 
Registered: Sep 2009
Location: Perth
Distribution: Manjaro
Posts: 10,006

Rep: Reputation: 3191Reputation: 3191Reputation: 3191Reputation: 3191Reputation: 3191Reputation: 3191Reputation: 3191Reputation: 3191Reputation: 3191Reputation: 3191Reputation: 3191
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
 
1 members found this post helpful.
Old 08-19-2017, 01:45 PM   #6
MadeInGermany
Senior Member
 
Registered: Dec 2011
Location: Simplicity
Posts: 2,790

Rep: Reputation: 1201Reputation: 1201Reputation: 1201Reputation: 1201Reputation: 1201Reputation: 1201Reputation: 1201Reputation: 1201Reputation: 1201
You can work on the previous line like this
Code:
if read line
then
  while read nextline
  do
    ...
    line=$nextline
  done
  printf "%s/n" "$line"
fi
 
1 members found this post helpful.
Old 08-20-2017, 10:01 AM   #7
vincix
Senior Member
 
Registered: Feb 2011
Distribution: Ubuntu, Centos
Posts: 1,240

Original Poster
Rep: Reputation: 103Reputation: 103
Hi,
I'm trying to take it one at a time.

@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?
 
Old 08-20-2017, 10:40 AM   #8
pan64
LQ Addict
 
Registered: Mar 2012
Location: Hungary
Distribution: debian/ubuntu/suse ...
Posts: 21,836

Rep: Reputation: 7308Reputation: 7308Reputation: 7308Reputation: 7308Reputation: 7308Reputation: 7308Reputation: 7308Reputation: 7308Reputation: 7308Reputation: 7308Reputation: 7308
Code:
filename=$1
while read line
do
...
done <filenama
 
1 members found this post helpful.
Old 08-20-2017, 11:00 AM   #9
vincix
Senior Member
 
Registered: Feb 2011
Distribution: Ubuntu, Centos
Posts: 1,240

Original Poster
Rep: Reputation: 103Reputation: 103
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
 
Old 08-20-2017, 11:55 AM   #10
pan64
LQ Addict
 
Registered: Mar 2012
Location: Hungary
Distribution: debian/ubuntu/suse ...
Posts: 21,836

Rep: Reputation: 7308Reputation: 7308Reputation: 7308Reputation: 7308Reputation: 7308Reputation: 7308Reputation: 7308Reputation: 7308Reputation: 7308Reputation: 7308Reputation: 7308
that is something called practice.
glad to help you
 
Old 02-06-2018, 07:40 AM   #11
vincix
Senior Member
 
Registered: Feb 2011
Distribution: Ubuntu, Centos
Posts: 1,240

Original Poster
Rep: Reputation: 103Reputation: 103
Quote:
Originally Posted by MadeInGermany View Post
You can work on the previous line like this
Code:
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?
 
Old 02-06-2018, 08:39 AM   #12
MadeInGermany
Senior Member
 
Registered: Dec 2011
Location: Simplicity
Posts: 2,790

Rep: Reputation: 1201Reputation: 1201Reputation: 1201Reputation: 1201Reputation: 1201Reputation: 1201Reputation: 1201Reputation: 1201Reputation: 1201
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.
 
Old 02-23-2018, 08:14 AM   #13
vincix
Senior Member
 
Registered: Feb 2011
Distribution: Ubuntu, Centos
Posts: 1,240

Original Poster
Rep: Reputation: 103Reputation: 103
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
 
Old 02-23-2018, 08:35 AM   #14
pan64
LQ Addict
 
Registered: Mar 2012
Location: Hungary
Distribution: debian/ubuntu/suse ...
Posts: 21,836

Rep: Reputation: 7308Reputation: 7308Reputation: 7308Reputation: 7308Reputation: 7308Reputation: 7308Reputation: 7308Reputation: 7308Reputation: 7308Reputation: 7308Reputation: 7308
just think about the following:
Code:
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
 
Old 02-23-2018, 09:46 AM   #15
vincix
Senior Member
 
Registered: Feb 2011
Distribution: Ubuntu, Centos
Posts: 1,240

Original Poster
Rep: Reputation: 103Reputation: 103
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.
 
  


Reply



Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
BASH: Read entire file line in for loop clinton Programming 16 04-18-2013 12:06 PM
[SOLVED] bash - print in a file on the same first line in a loop Hoxygen232 Linux - Newbie 20 01-28-2013 05:16 AM
[SOLVED] Bash loop over multi-line blocks zx_ Linux - Newbie 5 02-26-2012 11:02 AM
[SOLVED] bash for loop - all responses on one line genderbender Programming 10 11-19-2010 05:52 AM
Bash - Getting a for loop to process variables with a space in them davee Linux - General 4 10-08-2005 11:21 AM

LinuxQuestions.org > Forums > Linux Forums > Linux - Newbie

All times are GMT -5. The time now is 05:22 AM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration