java, ruby, python, php, religion, theism, atheism, ignosticism, portfolio, canada, programming, ruby sucks, python sucks, java rocks

Creating a New Bash Script From Within Another Script

Posted January 15, 2010

Today, I started writing a Bash script which installed a bunch of software, and needed to create a new script which the user could execute. I wanted this installer to be a single file, so the question arose how to create a new script?

I really didn't want to 'echo' a bunch of lines piped into a test file, so I figured perhaps I could somehow embed the new script inside the one I was running. Needless to say, this proved more difficult than one would imagine, since Bash itself has very poor regular expression parsing, and all the command-line tools provided in Linux are very "line" centric.

After hours of head-bashing, this is basically what I came up with (this is simplified to show the concept):

#!/bin/sh
# use grep to locate the byte which contains our marker
FIND_MARK=`grep -b "\#MARK-\{2\}" $0`
# extract the number part
POS=`expr $FIND_MARK : "\([0-9]\+\)"`
# get this file's size
THIS_FILE=`cat $0`
THIS_SIZE=`expr length "$THIS_FILE"`
# calculate where to read FROM THE END
BYTES=`expr $THIS_SIZE - $POS`
# remember to drop the marker
BYTES=`expr $BYTES - 7`
# extract the part we want
tail -c $BYTES $0 > test2.sh
chmod +x test2.sh
# we must always include this, to prevent accidentally running the rest
exit

#MARK--
#!/bin/sh
echo "BOO!"
exit

Is it pretty? Not by a long shot. I personally feel there's far too many variables involved here, but I can't seem to figure out how to get one command to use data from another quite the way I need it do (i.e. not using the venerable "|" piping).

I certainly hopes this saves others a bit of time.

AMENDMENT

After some experimentation, I've been able to reduce the size of the code required thus:

#!/bin/sh
# use grep to locate the byte which contains our marker, and expr to extract the numberic data
POS=`expr "\`grep -b \"\#MARK-\{2\}\" $0\`" : "\([0-9]\+\)"`
# get this file's size by getting the length in bytes of a string dump of the file
THIS_SIZE=`expr length "\`cat $0\`"`
## calculate where to read FROM THE END - remember to drop the marker (-6)
BYTES=`expr \`expr $THIS_SIZE - $POS\` - 6`
# extract the part we want
tail -c $BYTES $0 > test2.sh
chmod +x test2.sh
# we must always include this, to prevent accidentally running the rest
exit

#MARK--
#!/bin/sh
echo "BOO!"
exit

Comments

There are no comments for this post.

Add comment

Visit my Friends and Family

If you've enjoyed my site, please take a moment to visit my friends and family, many of whom have some interesting insights, and entertaining thoughts and ideas.

Widgets

Advertising


Windows 7 Sins
 

ss_blog_claim=07d81221ccea23e9eae5fdaf510cea20