Tag Archives: bash here-document

Self-extracting Shell Script

Self-extracting executables are a commonplace in Windows. Can it be or something like it be created in Linux, as well? If the question is CAN it be done for Linux, the answer to most “can” questions in open source world is a “yes”. But one does not need to be a copycat of Windows, when better things can be done in Linux – a self-extracting Shell Script.

For that, we just need to write a shell script, say generate_self_extracting_shell_script.sh. This script will take the directory to be self-extracted and output the self-extracting shell script. But how does this self-extracting shell script work? Basically, there are two parts in this script: 1) the bottom one containing the compressed tar of the directory to be self-extracted, and 2) the top one containing the shell script to extract the bottom part. So, when one runs this shell script, it would run the top part extracting the bottom part. These two parts are demarcated by a unique marker for the top part to identify its bottom. Here is how a typical self-extracting shell script will look like with TGZ_CONTENT as the unique marker:

#!/bin/bash

echo -n "Extracting script contents ... "
start_line_of_tar=$((`grep -an "^TGZ_CONTENT$" $0 | cut -d: -f1` + 1))
tail -n+${start_line_of_tar} $0 | tar zxf -
echo "done"
exit 0
TGZ_CONTENT
<compressed_tar_of_the_directory_goes_here>

The grep-cut pair extracts the line number of this script having TGZ_CONTENT, and then 1 is added to it to get the start_line_of_tar. Then, tail-tar pair extracts the tar, starting from start_line_of_tar till the end of the shell script file. The “exit 0” is important to stop the script execution after its top part is executed, as the bottom part is not really a script.

Now, here’s the script generate_self_extracting_shell_script.sh to generate the above self-extracting shell script:

#!/bin/bash

if [ $# -ne 2 ]
then
	echo "Usage: $0 <directory_to_package> <self_extracting_script_file>"
	exit 1
fi

directory=$1
script=$2

cat > ${script} <<SCRIPT_TOP
#!/bin/bash

echo -n "Extracting script contents ... "
start_line_of_tar=\$((\`grep -an "^TGZ_CONTENT$" \$0 | cut -d: -f1\` + 1))
tail -n+\${start_line_of_tar} \$0 | tar zxf -
echo "done"
exit 0
TGZ_CONTENT
SCRIPT_TOP
tar zcf - ${directory} >> ${script}

chmod +x ${script}

The two SCRIPT_TOP above are the delimiters for here-document (content from here) to be put into the generated shell script file. The tar line after that is to add the bottom content of the script. Notice the \ before the $ in the here-document, so as to not evaluate those in this script, but output verbatim into the self-extracting shell script.

Assuming an existing directory XYZ to be packaged into the self-extracting shell script xyz.sh, this script could be run as follows:

$ ./generate_self_extracting_shell_script.sh XYZ xyz.sh

And running the xyz.sh shell script would extract back the XYZ directory, thus xyz.sh becoming a self-extracting shell script.

   Send article as PDF