开发者

Storing files inside BASH scripts

Is there a way to store binary data inside a BASH script so that it can be piped to a pro开发者_运维问答gram later in that script?

At the moment (on Mac OS X) 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?


Base64 encode it. For example:

$ openssl base64 < sound.m4a

and then in the script:

S=<<SOUND
YOURBASE64GOESHERE
SOUND

echo $S | openssl base64 -d | play


I know this is like riding a dead horse since this post is rather old, but I'd like to improve Sionide21 answer as his solution stores the binary data in a variable which is not necessary.

openssl base64 -d <<SOUND | play
YOURBASE64DATAHERE
SOUND

Note: HereDoc Syntax requires that you don't indent the last 'SOUND' and base64 decoding sometimes failed on me when i indented that 'YOURBASE64DATAHERE' section. So it's best practice to keep the Base64 Data as well the end-token unindented.

I've found this looking for a more elegant way to store binary data in shell scripts, but i had already solved it like described here. Only difference is I'm transporting some tar-bzipped files this way. My platform knows a separate base64 binary so I don't have to use openssl.

base64 -d <<EOF | tar xj
BASE64ENCODEDTBZ
EOF


There is a Unix format called shar (shell archive) that allows you to store binary data in a shell script. You create a shar file using the shar command.


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.


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


If it's a single block of data to use, the trick I've used is to put a "start of data" marker at the end of the file, then use sed in the script to filter out the leading stuff. For example, create the following as "play-sound.bash":

#!/bin/bash

sed '1,/^START OF DATA/d' $0 | play
exit 0
START OF DATA

Then, you can just append your data to the end of this file:

cat sound.m4a >> play-sound.bash

and now, executing the script should play the sound directly.


Since Python is available on OS X by default, you can do as below:

ENCODED=$(python -m base64 foo.m4a)

Then decode it as below:

echo $ENCODED | python -m base64 -d  | play
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜