LinuxQuestions.org
Download your favorite Linux distribution at LQ ISO.
Home Forums Tutorials Articles Register
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices


Reply
  Search this Thread
Old 08-13-2016, 02:57 AM   #1
Michael Uplawski
Senior Member
 
Registered: Dec 2015
Posts: 1,622
Blog Entries: 40

Rep: Reputation: Disabled
sed-less word wrap in Bash


Good morning,

can someone help me compose or develop a command line for a bash-script that will wrap a given expression from "$1" before a given line-limit and at a given delimiter? I have done a lot of experimenting with cut -c and -f and tr to insert line-breaks, for-loops with expr() to break the expression into lines. There have been good results, but some texts just would not be formatted correctly for my uses. The main problem is probably my abstinence from sed.

So the given initial values shall be those in the following example and what I am lacking is the intelligence to make the remainder of the script run correctly.

Code:
expression="$1"
delimiter="$2"
limit="$3"

if [ "$delimiter" == ' ' ]
then
    delimiter=' '
fi
if [ "$limit" == ' ' ]
then 
    limit=40
fi

# ATTN! no call to sed below this line
# -----------------------------------
# Thank Youhou.
(...)
For the time, I call from my shell-scripts a small c++ program which does the wrapping, mainly to ensure that text of arbitrary origin is wrapped in a yad generated text-info box.

Otherwise, it is necessary to scroll, and sometimes a long way, to the right of the yad-dialog.

I feel, that the call to the binary “wrap-tool” is a little exaggerated. C/C++ code attached.
Attached Files
File Type: txt main.cpp.txt (1.2 KB, 10 views)

Last edited by Michael Uplawski; 08-16-2016 at 12:28 AM. Reason: expr is not a good variable. Call it expression. Orthography... clarifying additions.
 
Old 08-13-2016, 05:18 AM   #2
grail
LQ Guru
 
Registered: Sep 2009
Location: Perth
Distribution: Manjaro
Posts: 10,008

Rep: Reputation: 3193Reputation: 3193Reputation: 3193Reputation: 3193Reputation: 3193Reputation: 3193Reputation: 3193Reputation: 3193Reputation: 3193Reputation: 3193Reputation: 3193
I think I follow, so maybe something like:
Code:
#!/usr/bin/env bash

expression="$1"
(( $# >= 2 )) && delimiter="$2" || delimiter=' '
(( $# == 3 )) && limit="$3"     || limit=40

# Split data based on delimiter value
IFS="$delimiter"
output=( $expression )
unset IFS

# Only output length of line based on limit
for line in "${output[@]}"
do
  while (( ${#line} > limit ))
  do
    echo "${line:0:limit}"
    line="${line:limit}"
  done
echo $line
done
There are some edge cases you would need to allow for and probably some other error checking at the start, but it should give you an idea
 
1 members found this post helpful.
Old 08-13-2016, 06:01 AM   #3
Michael Uplawski
Senior Member
 
Registered: Dec 2015
Posts: 1,622

Original Poster
Blog Entries: 40

Rep: Reputation: Disabled
Quote:
Originally Posted by grail View Post
There are some edge cases you would need to allow for and probably some other error checking at the start, but it should give you an idea
This is good stuff!
All the elements are there and I do not spot a single ‘sed’.

But I have to admit, that it does the thing “the wrong way around”, probably because of my clumsy description, above. Do not worry, though. Your example motivates me to adapt it to my needs.

Just to show you what I have failed to explain, an example string, processed “both ways”:

Code:
This shall be a longer line of text, athough, ... wait, better this: "Oh but I was so much older then, I'm younger than that now"
If I call your script on the text, I get:
Code:
user@machine:/tmp$ ./wrap_sh "This shall be a longer line of text, although, ... wait, better this: \"Oh but I was so much older then, I'm younger than that now\"" " " 10
This
shall
be
a
longer
line
of
text,
although,
...
wait,
better
this:
"Oh
but
I
was
so
much
older
then,
I'm
younger
than
that
now"
Now the same with my incredibly marvelous wrap-tool:
Code:
user@machine:/tmp$ wrap "This shall be a longer line of text, although, ... wait, better this: \"Oh but I was so much older then, I'm younger than that now\"" " " 10
This shall
be a longer
line of
text, although,
... wait,
better
this: "Oh
but I was
so much
older then,
I'm younger
than that
now"
The difference is that a line-break does always replace a blank, but never before the indicated line-length (10). <-- This phrase is missing from my first post. Worse! I wrote “before a given line-limit”, meaning, that the line must be limited to some upper value, although readability requires that it be wrapped “after a minimum line-length”. The given line-limit is not the third parameter to the script, but the lateral limit of a graphical text box. Sorry.

Last edited by Michael Uplawski; 08-13-2016 at 06:13 AM. Reason: post, not posting. Worse.
 
Old 08-13-2016, 07:23 AM   #4
Michael Uplawski
Senior Member
 
Registered: Dec 2015
Posts: 1,622

Original Poster
Blog Entries: 40

Rep: Reputation: Disabled
A first working script, not yet thoroughly tested but it produces the same result as the C++-tool from the example-string in the previous post.

Code:
#!/usr/bin/env bash

expression="$1"
(( $# >= 2 )) && delimiter="$2" || delimiter=' '
(( $# == 3 )) && limit="$3"     || limit=40

# Split data based on delimiter value
IFS="$delimiter"
output=( $expression )
unset IFS

# Only output length of line based on limit
out=''
fraction=''
for line in "${output[@]}"
do
	#echo "fraction is $fraction (${#fraction})"

	if [ ${#fraction} -lt $limit ]
	then
		fraction="$fraction$delimiter$line"
	else
		out="$out$fraction"
		fraction="\n$line"
	fi
done
out="$out$fraction"

echo -e "${out:1}"
What bugs me still is the repeated line out="$out$fraction". A footer-controlled loop (do...while) is needed and I will lookup the shell-syntax, once my connection speed is up again (linuxquestions.org is one of the few sites that always charge quickly).

Probably [SOLVED] and thanks again.

Ah. Wait. I want to mention, that an alternative approach comprised a $(expr ${#out} % $limit) and I still consider the idea worth some thinking... but alas! It caused some headache, instead.

And... (edit II). Looking at this script solution, I wonder again, if I should not just stick with my wrap-tool anyway.

Last edited by Michael Uplawski; 08-13-2016 at 07:37 AM. Reason: Modulo. Doubt.
 
Old 08-13-2016, 08:36 AM   #5
grail
LQ Guru
 
Registered: Sep 2009
Location: Perth
Distribution: Manjaro
Posts: 10,008

Rep: Reputation: 3193Reputation: 3193Reputation: 3193Reputation: 3193Reputation: 3193Reputation: 3193Reputation: 3193Reputation: 3193Reputation: 3193Reputation: 3193Reputation: 3193
awk, sed, perl or other can probably do this in a cleaner way, but the bash challenge is still a nice solution. I am not sure on the reason for a delimiter if you are going to then ignore it by saying the
limit is the overriding factor. It is probably that I do not understand the real intention of the code or if the delimiter is actually important, maybe just switch the order so length transition is performed first??

Ultimately, if you have a tool that works and no need to incorporate any other bashisms, then probably just use the tool you have
 
Old 08-13-2016, 10:21 AM   #6
danielbmartin
Senior Member
 
Registered: Apr 2010
Location: Apex, NC, USA
Distribution: Mint 17.3
Posts: 1,881

Rep: Reputation: 660Reputation: 660Reputation: 660Reputation: 660Reputation: 660Reputation: 660
Quote:
Originally Posted by grail View Post
awk, sed, perl or other can probably do this in a cleaner way ...
Consider the fold command. With this InFile ...
Code:
This shall be a longer line of text, although, ... wait, better this: "Oh but I was so much older then, I'm younger than that now"
... this fold ...
Code:
fold -sw40 $InFile >$OutFile
... produced this OutFile ...
Code:
This shall be a longer line of text, 
although, ... wait, better this: "Oh 
but I was so much older then, I'm 
younger than that now"
Change the 40 to suit your purpose.

Daniel B. Martin

Last edited by danielbmartin; 08-13-2016 at 10:23 AM.
 
1 members found this post helpful.
Old 08-13-2016, 03:54 PM   #7
Michael Uplawski
Senior Member
 
Registered: Dec 2015
Posts: 1,622

Original Poster
Blog Entries: 40

Rep: Reputation: Disabled
Quote:
Originally Posted by danielbmartin View Post
Consider the fold command.
It is not necessary anymore, but I confirm that I did not know of the existence of the fold command. -sw40 is all I need.
However, as in this way fold just replaces my own compiled utility, the “courageous shell exercise” taught me something new and was necessary.

This discussion results in a new blog-post.

Last edited by Michael Uplawski; 08-16-2016 at 01:56 AM.
 
  


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
Simulating Word Wrap with "probably" SED fsenes Linux - Newbie 6 04-16-2009 12:43 AM
using sed to remove word wrap Harpune Linux - Software 2 03-02-2009 06:53 PM
variable length string using GD (word wrap, carriage return, word/character count)? frieza Programming 1 02-14-2009 05:21 PM
"enscript --word-wrap" does not wrap line of text file powah Linux - General 3 05-16-2006 09:12 PM
Microsoft Word won't word wrap Micro420 General 1 06-13-2005 04:36 PM

LinuxQuestions.org > Forums > Non-*NIX Forums > Programming

All times are GMT -5. The time now is 08:36 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