3

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.)

user2064000
  • 3,096
  • 3
  • 26
  • 56

4 Answers4

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
loentar
  • 4,971
  • 1
  • 21
  • 24
  • 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 Mar 12 '21 at 15:50
4

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
l0b0
  • 52,149
  • 24
  • 132
  • 195
  • 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 Dec 24 '13 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 Dec 24 '13 at 11:46
1

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

aBarocio80
  • 946
  • 1
  • 7
  • 12
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
    
user1742529
  • 256
  • 4
  • 16