5

How would I go about making a self extracting archive that can be executed on sh?

The closest I have come to is:

extract_archive () {
    printf '<archive_contents>' | tar -C "$extract_dir" -xvf -
}

Where <archive_contents> contains a tarball with null characters, %, ' and \ characters escaped and enclosed between single quotes.

Is there any better way to do this so that no escaping is required?

(Please don't point me to shar, makeself etc. I want to write it from scratch.)

1

4 Answers 4

16

Alternative variant is to use marker for end of shell script and use sed to cut-out shell script itself.

Script selfextract.sh:

#!/bin/bash

sed '0,/^#EOF#$/d' $0 | tar zx; exit 0
#EOF#

How to use:

# create sfx
cat selfextract.sh data.tar.gz >example_sfx.sh

# unpack sfx
bash example_sfx.sh
1
  • You can do this in one command: { echo -e "#!/bin/bash\nsed '0,/^#EOF#\$/d' \$0 | tar xJvf -; exit 0\n#EOF#"; tar cfJ - program_to_extract; } > selfextract.sh
    – Tuxinose
    Commented Mar 12, 2021 at 15:50
3

Since shell scripts are not compiled, but executed statement by statement, you can mix binary and text content using a pattern like this (untested):

#!/bin/sh
sed -e '1,/^exit$/d' "$0" | tar -C "${1-.}" -zxvf -
exit
<binary tar gzipped content here>

You can add those two lines to the top of pretty much any tar+gzip file to make it self extractable.

To test:

$ cat header.sh
#!/bin/sh
sed -e '1,/^exit$/d' "$0" | tar -C "${1-.}" -zxvf -
exit
$ tar -czf header.tgz header.sh
$ cat header.sh header.tgz > header.tgz.sh
$ sh header.tgz.sh
header.sh
2
  • 1
    You could use a marker line END_OF_SCRIPT and the end of the script and sed -e '1,/END_'OF_SCRIPT/ "$0" (note that the sed command must not contain the marker literally - therefore the "misplaced" quote). This eliminates the need to adapt the end address when the number of lines of the script changes.
    – halfbit
    Commented Dec 24, 2013 at 11:40
  • Thanks @halfbit. I'm usually sceptical of such markers, since sed and similar programs are often greedy, but it turns out sed is not greedy in this case, so it can be used.
    – l0b0
    Commented Dec 24, 2013 at 11:46
1

Some good articles on how to do exactly that could be found at:

0

Yes, you can do it natively with xtar.

  1. Build xtar elf64 tar self-extractor header (you free to modify it to support elf32, pe and other executable formats), it is based on lightweight bsdtar untar and std elf lib.

    cc contrib/xtar.c -o ./xtar
    
  2. Copy xtar binary to yourTar.xtar

    cp ./xtar yourTar.xtar
    
  3. Append yourTar.tar archive to the end of yourTar.xtar

    cat yourTar.tar >> yourTar.xtar
    chmod +x yourTar.xtar
    

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.