Page 1 of 1

How to inject a wav file in to a bash script

Posted: Mon Aug 03, 2020 2:10 am
by Geoffrey
This is from the Murga Forum, first Posted: Sat 30 Dec 2017, I thought I'd retrieve the conversation, as it's an obscure process that hasn't found a use in puppy as far as I know.

I really hope the Murga Forum can be saved.

I am so grateful to all those that have added to the vast amount of knowledge that I have often accessed that helped me, I knew little to nothing before joining the Puppy forum, thank you everyone.
Geoffrey: I was wondering if was possible for a script to carry binary data, after a bit of searching I found the answer I was looking for, so made this example.

This script when run will extract the data to /tmp as chime.wav, then play the wav file as a sequence derived from the clock, to chime the hours.

Will work to chime the hours if run with Pschedule on the hour.

Code: Select all

#!/bin/bash

dd if="$0" of=/tmp/chime.wav bs=1 skip=131
hours=`date +"%-l"`
seq "$hours" | xargs -I{} aplay -q /tmp/chime.wav
exit;
In a working directory to build this place the chime.wav, then create a script with the above code and name it hour_chime

Code: Select all

cat chime.wav >> hour_chime
chmod +x hour_chime
Open a terminal in the working directory and paste the above code and run it, this injects the wav data in to the script.

The script is now a standalone not requiring any external file to function.

The important thing is the skip=? this needs to be precise else the extracted data will be corrupted.
MochiMoppel:
Geoffrey wrote:
I was wondering if was possible for a script to carry binary data

Nothing is impossible but it has the potential for desaster. Bash tries to interpret binary rubbish:

Code: Select all

# /opt/hour_chime
56954+0 records in
56954+0 records out
56954 bytes (57 kB) copied, 0.447853 s, 127 kB/s
/opt/hour_chime: line 6: $'exitRIFFr\336WAVEfmt': command not found
/opt/hour_chime: line 7: $'S\031\365\v\230\363=\b~\E\225\350y\317H\376\274\035\342\231\031&\374 \331\316\242\343\300\004\327\025\260': command not found
/opt/hour_chime: line 10: syntax error near unexpected token `)'
/opt/hour_chime: line 10: `)þÙâä×æ¶ïC % ð\ç«{*×?õrþºã]ڻõ)^0
                                                           wÛ9ãÕë¢õd"³)IüëßÄþá _në1íºõú¨õN¨õô¯µïYÌîóÐ#̹õæôXþ©ëñïö2ù«X+»r÷؍µTæÓ9<:4
              Ííçù÷Ü*û³:Â<÷.̟ÄéϾ'
# 1;2c1;2c^C	
Your exit command bumps into the header of the wav file, which makes it "exitRIFFr", i.e. your script will not exit at this point. Make it exit; and change the skip value to 131. Still I can't see the usefulness of this exercise.
Geoffrey:
MochiMoppel wrote:
Your exit command bumps into the header of the wav file, which makes it "exitRIFFr", i.e. your script will not exit at this point. Make it exit; and change the skip value to 131. Still I can't see the usefulness of this exercise.



Ah! thanks, updated the first post, more a curiosity than a having a purpose for it, then you never know when it may find a purpose, just handy to know it can be done.
MochiMoppel:
Geoffrey wrote:
more a curiosity than a having a purpose for it

That's a valid reason
Let's try to make it a bit smarter. There is no need to extract the audio data into a tmp file. You can make the bash script "play itself". Create a script, let's call it header:

Code: Select all

#!/bin/bash
for ((c=1;c<=$(date +%l);c++));do dd if="$0"  bs=1 skip=90 | aplay; done
exit;	
Make sure that the code has 90 characters, then combine header and chime.wav into a new script hourlychime.sh:

Code: Select all

cat header chime.wav > hourlychime.sh ; chmod +x  hourlychime.sh	
Running hourlychime.sh will pipe the embedded audio data directly to aplay.
From here there is no limit to insanity: You can add a timer loop, so you won't need pschedule, you can pack more than one audio file into this script and even a player ... OK, I leave it to your curiosity.
musher0:

Hi guys.

This technique is fascinating. Thanks to MochiMoppei for revisions and suggestions, and of
course to Geoffrey for initiating this thread.

Geoffrey, in the 1st line of your OP, you mention some research you did. Would you care to
share a few URLs about this technique for our benefit? TIA.

BTW, does this technique have a name?

BFN
_________________
musher0
~~~~~~~~~~
Je suis né pour aimer et non pas pour haïr. (Sophocle) /
I was born to love and not to hate. (Sophocles)
amigo:

Think about those *.run files -they are self-extracting scripts. The payload is a tarball or zipped file or whatever. Inside the script you have marker or other method to skip over the first script part, starting from the marker or offset and procesing that with whatever. You can use 'sed', 'head', 'cut', 'dd' or many other ways to skip to the payload and pipe that through whatever.

By appending such binary data, you can even have an 'exit' in your script to make sure the script will never get there.
Geoffrey:
MochiMoppel wrote:
Let's try to make it a bit smarter. There is no need to extract the audio data into a tmp file. You can make the bash script "play itself"
Brilliant, that was my initial want, I just got lazy Laughing
musher0 wrote:
share a few URLs about this technique for our benefit?
BTW, does this technique have a name?
https://stackoverflow.com/questions/276 ... fficiently
amigo wrote:
Think about those *.run files -they are self-extracting scripts.


That had crossed my mind during my search http://makeself.io/
seaside:

Here's another way using tail.

Code: Select all

#!/bin/bash
#chime.wav
#cat header chime.wav > hourlychime.sh ; chmod +x  hourlychime.sh
hours=`date +"%-l"`
size=`stat -c %s chime.wav`
for (( i=1; i <= $hours; i++ )); do  tail -c $size hourlychime.sh | aplay;  done
exit;	

Cheers,
s
musher0:

Thanks, Geoffrey.

I wish you and all Puppyists a "Happy, Healthy and Successful New Year 2018"! Smile
_________________
musher0
~~~~~~~~~~
Je suis né pour aimer et non pas pour haïr. (Sophocle) /
I was born to love and not to hate. (Sophocles)
vovchik:

Dear all,

Thanks for the examples. I learned something, as I usually from many posts on this forum. I wish you all a happy, prosperous and rewarding new year!

WIth kind regards,
vovchik
Geoffrey:
seaside wrote:
Here's another way using tail.

Code: Select all

#!/bin/bash
#chime.wav
#cat header chime.wav > hourlychime.sh ; chmod +x  hourlychime.sh
hours=`date +"%-l"`
size=`stat -c %s chime.wav`
for (( i=1; i <= $hours; i++ )); do  tail -c $size hourlychime.sh | aplay;  done
exit;	

Cheers,
s



That's good, here's a script to create the hourlychime.sh, just drag the wav file to it

Code: Select all

#!/bin/bash
SCRIPT="hourlychime.sh"
touch "$SCRIPT"
echo '#!/bin/bash
SCRIPT="$(readlink -e "$0")"
for (( i=1; i <= `date +"%-l"`; i++ )); do  tail -c '$"`stat -c %s "$1"`"' "$SCRIPT" | aplay -q;  done
exit;' > "$SCRIPT"
cat "$1" >> "$SCRIPT" ; chmod +x  "$SCRIPT"



Happy new year

EDIT: Strangely enough this doesn't work from outside the directory it's in, I need to change directory in terminal for it to run, even if it's in /usr/bin

EDIT 2: fixed tail couldn't find the path

Code: Select all

SCRIPT="$(readlink -e "$0")"
musher0:

Powerful stuff. Careful what you wish!!! Wink
Someone could hide a < remove all command > in there!
_________________
musher0
~~~~~~~~~~
Je suis né pour aimer et non pas pour haïr. (Sophocle) /
I was born to love and not to hate. (Sophocles)
jamesbond:
amigo wrote:
Think about those *.run files -they are self-extracting scripts. The payload is a tarball or zipped file or whatever.
Here: http://makeself.io/
It's actually quite popular. VirtualBox generic Linux binaries for example are packaged with makeself. Nvidia proprietary drivers too.