LinuxQuestions.org
Visit Jeremy's Blog.
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-22-2006, 11:39 PM   #1
sixerjman
Member
 
Registered: Sep 2004
Distribution: Debian Testing / Unstable
Posts: 180
Blog Entries: 1

Rep: Reputation: 32
Bash script - how to reassemble file from array


OK I'm attempting to work through the exercises in the Advanced Bash Scripting Guide. In the 'EASY' section (HA HA HA) there's an exercise to write a script that echoes itself to stdout backwards. I'm going on day 3 so I may have strayed horribly off-path and built a monstrosity that's totally unnecessary but I'm almost at the end.

The basic outline of the script logic is to:

1) read each character of the script and assign it to an array element.

2) Figure out the length of the array, then start echoing the characters in reverse order (starting at the end and moving back).

The problem is that since only one character is read (via read -n1), on output a line feed follows each character. If I use 'echo -n' the characters are output as one long string and even the 'true' linefeeds which exist in the script are not echoed.

I can reassemble words with the following ugly kludge:

cat junk | tr '\n' Z | sed 's/ZZ/\n/g' | sed 's/Z//'g

where 'junk' is a file containing each character on a separate line. Any help anybody can offer would be appreciated, so I can move on to the next challenge. Thanks in advance!

Here is the script:

#!/bin/bash
#
# absxm2e4.sh
# -----------
#
# Backwards Listing
#
# Write a script that echoes itself to stdout, but backwards.
#
WORKFILE=/tmp/$(basename $0).work
#BWFILE=$(mktemp)
BWFILE=$HOME/scripts/junk
echo "Temporary file is: $BWFILE"
NEWLINE="\n"

cat $0 > $WORKFILE # Write file to temporary file

exec 3<&0 # Save old stdin file handle
exec 0<$WORKFILE # Set stdin to this file
index=0 # array index
declare -a filearray # declare the character array

# Build filearray by loading each character
while read -n1 c
do
filearray[$index]=$c
let index=index+1
done
echo ${filearray[@]}

echo "The length of the filearray is: ${#filearray[@]}."
arraylen=${#filearray[@]}

# Now build the backwards array
let bwindex=arraylen-1
while [ $bwindex -ge 0 ]
do
echo ${filearray[$bwindex]} >> $BWFILE
let bwindex=bwindex-1 # Decrement array index
done

cat $BWFILE

exec 0<&3 # Restore stdin

exit 0
 
Old 08-23-2006, 12:25 AM   #2
alunduil
Member
 
Registered: Feb 2005
Location: San Antonio, TX
Distribution: Gentoo
Posts: 684

Rep: Reputation: 62
Maybe sort will do what you need, but I don't know if you would call that cheating either...

Regards,

Alunduil
 
Old 08-23-2006, 01:07 AM   #3
sixerjman
Member
 
Registered: Sep 2004
Distribution: Debian Testing / Unstable
Posts: 180

Original Poster
Blog Entries: 1

Rep: Reputation: 32
Bash script to reassemble file from character array

Thanks for the reply? How would I use sort to create a reversed listing of the script?

Currently I have a character array of the script in reverse order. To use a short example, consider this segment of the array (which I have saved to a file):

#

h
s
a
b
/
n
i
b
!
#

I need to convert that to:

#
hsab/nib!#

I was thinking sed would be the tool to use but the problem is sed creates a 'pattern space' for each line, and if I delete newlines, I'm left with one long string.
 
Old 08-23-2006, 02:41 AM   #4
sixerjman
Member
 
Registered: Sep 2004
Distribution: Debian Testing / Unstable
Posts: 180

Original Poster
Blog Entries: 1

Rep: Reputation: 32
OK, here's two 'cheating ways'

#!/bin/bash
rev $(basename $0) | tac

Nice and succinct, but not very instructive. Here's two sed commands to do the job (from the famous sed one-liners):

#!/bin/bash
sed -n '1!G;h;$p' $(basename $0) | \
sed '/\n/!G;s/\(.\)\(.*\n\)/&\2\1/;//D;s/.//'

ACK! I can barely read that second one, let alone think to write it, so again, not very instructive, unless the point of the exercise was
to find the sed one-liners.
 
Old 08-23-2006, 04:15 PM   #5
archtoad6
Senior Member
 
Registered: Oct 2004
Location: Houston, TX (usa)
Distribution: MEPIS, Debian, Knoppix,
Posts: 4,727
Blog Entries: 15

Rep: Reputation: 234Reputation: 234Reputation: 234
2 things that would help that 2nd one:
  • the -r option --
    Quote:
    -r, --regexp-extended
    use extended regular expressions in the script.
  • using ',' not '/' for the delimiter
Code:
sed '/\n/!G;s/\(.\)\(.*\n\)/&\2\1/;//D;s/.//'
# becomes (I hope)
sed -r '/\n/!G;s,(.)(.*\n),&\2\1,;//D;s,.,,'
I still don't know what "/\n/!G;" & "//D;" do ...
 
Old 08-23-2006, 07:10 PM   #6
sixerjman
Member
 
Registered: Sep 2004
Distribution: Debian Testing / Unstable
Posts: 180

Original Poster
Blog Entries: 1

Rep: Reputation: 32
sed separator and 'rev' operation

Thanks for the reply! Yes, I was just reading up and found separator characters other than '/' can be used. The example given is a colon,
comma should do as well.

OK, lets attempt to break this thing down operation by operation and
if I can understand that I'll consider the exercise finished because I'll have a solution I can understand. Maybe it will shed some light on a possible solution from building the desired output from the character array I have.

sed '/\n/!G;s/\(.\)\(.*\n\)/&\2\1/;//D;s/.//'
---------------------------------------------
1) sed '/\n/!G - If newline is matched, don't copy hold space to pattern space, otherwise do. Has the effect of double spacing the
file, which is expressed in a simpler fashion by 'sed G'.

2) s/\(.\)\(.*\n\)/&\2\1/ - Will get to this later...
 
Old 08-23-2006, 07:22 PM   #7
sixerjman
Member
 
Registered: Sep 2004
Distribution: Debian Testing / Unstable
Posts: 180

Original Poster
Blog Entries: 1

Rep: Reputation: 32
//D operation -

From 'man sed':

D Delete up to the first embedded newline in the pattern space. Start next cycle, but skip reading from the
input if there is still data in the pattern space.

What it does in the context of the script I'm still trying to figure out...

P.S. Eniad, huh? I only go back to IBM/1401 ;-)
 
Old 08-24-2006, 01:30 AM   #8
JZL240I-U
Senior Member
 
Registered: Apr 2003
Location: Germany
Distribution: openSuSE Tumbleweed-KDE, Mint 21, MX-21, Manjaro
Posts: 4,629

Rep: Reputation: Disabled
Maybe a stupid question for the experts: aren't there pipes / special devices in linux with LIFO characteristics? My eyes hurt when I look at the sed command...

 
Old 08-24-2006, 10:44 AM   #9
sixerjman
Member
 
Registered: Sep 2004
Distribution: Debian Testing / Unstable
Posts: 180

Original Poster
Blog Entries: 1

Rep: Reputation: 32
Named pipes, LIFO, sed ugliness

There are FIFO pipes (man mkfifo). LIFO operations are analogous to stacks. Bash builtins PUSHD and POPD are used to access and manipulate the directory stack (DIRSTACK). I don't know of any other LIFO constructs associated with Bash.

The reason I'm concentrating on sed are:

1) The sed one-liner above is the solution to the exercise I'm working on.
2) Sed is ubiquitous in the Linux system scripts (startup/shutdown, maintenance etc.).
3) It is a powerful stream editor which lends itself well to scripts to perform repetitive tasks without having to write a separate program in C or whatever.

Having said all that, yes, it is U-G-L-Y UGLY. But I'm finding that the more about the syntax I learn the easier it is to read and decipher the operations. About half the characters in many of the substitions are escapes ('\n'), and it helps to mentally strip those out (or physically with a pencil and paper), leaving only the regular expression(s) and sed commands.
 
Old 08-24-2006, 09:59 PM   #10
sixerjman
Member
 
Registered: Sep 2004
Distribution: Debian Testing / Unstable
Posts: 180

Original Poster
Blog Entries: 1

Rep: Reputation: 32
It's over, I give up (for now)

ABS covers the 'rev' command in Chapter 12 Section 1 "Basic Commands". So be it:

#!/bin/bash
#
# absxm2e4.sh
# -----------
#
# Backwards Listing
#
# Write a script that echoes itself to stdout, but backwards.
#
rev $(basename $0)

exit 0
 
Old 08-25-2006, 01:04 AM   #11
JZL240I-U
Senior Member
 
Registered: Apr 2003
Location: Germany
Distribution: openSuSE Tumbleweed-KDE, Mint 21, MX-21, Manjaro
Posts: 4,629

Rep: Reputation: Disabled
Wow, that's a relief .
 
Old 08-25-2006, 11:45 AM   #12
sixerjman
Member
 
Registered: Sep 2004
Distribution: Debian Testing / Unstable
Posts: 180

Original Poster
Blog Entries: 1

Rep: Reputation: 32
Ha Ha Ha

Indeed. My head feels much better after I stopped banging it against that pesky brick wall. Once again, thanks to all for the replies all. :-D
 
  


Reply

Tags
option, sed



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 shell script split array robertngo Programming 13 06-19-2011 11:01 PM
Bash Script Array index value Kedelfor Programming 10 04-29-2009 04:37 AM
Bash script text line into an array toolshed Programming 1 06-13-2005 05:49 PM
[bash] Put words from file to array mispunt Programming 4 11-04-2004 10:53 AM
MAJOR problem ... bash script array HELP !!!!! michael_util Slackware 1 02-13-2004 06:51 AM

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

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