tags:

views:

86

answers:

4

Is there a way to store binary data inside a BASH script so that it can be piped to a program later in that script?

At the moment (on Mac OS) I'm doing

play sound.m4a
# do stuff

I'd like to be able to do something like:

SOUND <<< the m4a data, encoded somehow?
END
echo $SOUND | play
#do stuff

Is there a way to do this?

+1  A: 

When I've done this I've used a shell here document piped through atob.

function emit_binary {
  cat << 'EOF' | atob
  --junk emitted by btoa here
  EOF
}

the single quotes around 'EOF' prevent parameter expansion in the body of the here document.

atob and btoa are very old programs, and for some reason they are often absent from modern Unix distributions. A somewhat less efficient but more ubiquitous alternative is to use mimencode -b instead of btoa. mimencode will encode into base64 ASCII. The corresponding decoding command is mimencode -b -u instead of atob. The openssl command will also do base64 encoding.

Norman Ramsey
Those two commands don't seem to be present on Mac OSX.
Sionide21
@Sionide: Follow the link for source code, or you could use `mimencode`.
Norman Ramsey
A: 

Here's some code I wrote a long time ago that packs a choice executable into a bash script. I can't remember exactly how it works, but I suspect you could pretty easily modify it to do what you want.

#!/usr/bin/perl

use strict;

print "Stub Creator 1.0\n";

unless($#ARGV == 1)
{
    print "Invalid argument count, usage: ./makestub.pl InputExecutable OutputCompressedExecutable\n";
    exit;
}

unless(-r $ARGV[0])
{
    die "Unable to read input file $ARGV[0]: $!\n";
}

my $OUTFILE;
open(OUTFILE, ">$ARGV[1]") or die "Unable to create $ARGV[1]: $!\n";

print "\nCreating stub script...";

print OUTFILE "#!/bin/bash\n";
print OUTFILE "a=/tmp/\`date +%s%N\`;tail -n+3 \$0 | zcat > \$a;chmod 700 \$a;\$a \${*};rm -f \$a;exit;\n";

close(OUTFILE);

print "done.\nCompressing input executable and appending...";
`gzip $ARGV[0] -n --best -c >> $ARGV[1]`;
`chmod +x $ARGV[1]`;

my $OrigSize;
$OrigSize = -s $ARGV[0];

my $NewSize;
$NewSize = -s $ARGV[1];

my $Temp;

if($OrigSize == 0)
{
    $NewSize = 1;
}

$Temp = ($NewSize / $OrigSize) * 100;
$Temp *= 1000;
$Temp = int($Temp);
$Temp /= 1000;

print "done.\nStub successfully composed!\n\n";
print <<THEEND;
Original size: $OrigSize
New size:      $NewSize
Compression:   $Temp\%

THEEND
Nextraztus
+1  A: 

There is a unix format called shar (shell archive) http://en.wikipedia.org/wiki/Shar that allows you to store binary data in a shell script. You create a shar file using the shar command (it's on MacOS Snow Leopard, probably others).

Joshua Smith
+3  A: 

Base64 encode it. For example:

$ openssl base64 < sound.m4a

and then in the script:

S=<<SOUND
YOURBASE64GOESHERE
SOUND

echo $S | openssl base64 -d | play
Sionide21
Does what it says on the tin - cheers!
JP