【问题标题】:Embed a Executable Binary in a shell script在 shell 脚本中嵌入可执行二进制文件
【发布时间】:2012-05-16 12:41:38
【问题描述】:

首先,我已经在 Google 上搜索过,但只找到了将压缩文件(比如 .tar.gz)嵌入到 shell 脚本中的示例。

基本上,如果我有一个打印字符串的 C 程序 (hello.c),比如说 Hello World!

我编译它以获得可执行的二进制文件

gcc hello.c -o hello

现在我有一个 shell 脚本 testEmbed.sh

我要问的是是否可以将二进制文件 (hello) 嵌入到 shell 脚本中,以便在我运行时

./testEmbed.sh

它执行二进制文件以打印 Hello World!

说明: 一种替代方法是我将可执行文件压缩到存档中,然后在脚本运行时将其解压缩。我要问的是是否可以在没有它的情况下运行该程序。

到目前为止,我一直在尝试here的方法。但这对我不起作用。我猜作者是在另一个架构上使用其他发行版。所以,基本上这对我不起作用。 :P

另外,如果 C 程序的工作流程与 Java jar 不同,我也想知道!

【问题讨论】:

    标签: java c shell binary


    【解决方案1】:

    是的,这是可以做到的。它实际上与您链接的文章在概念上非常相似。诀窍是使用uuencode 将二进制文件编码为文本格式,然后将其附加到脚本的末尾。

    然后您的脚本以这样的方式编写:它在自身上运行 uudecode 以创建一个二进制文件,更改权限然后执行它。

    uuencodeuudecode 最初是为了将二进制内容转移到互联网的前身,而互联网并不能很好地处理二进制信息。转换为文本意味着它也可以作为 shell 脚本提供。如果由于某种原因您的发行版在您尝试运行uuencode 时出现问题,这可能意味着您必须安装它。例如,在 Debian Squeeze 上:

    sudo aptitude install sharutils
    

    将为您获取相关的可执行文件。这是我经历的过程。首先创建并编译你的C程序hello.c:

    pax> cat hello.c
    
    #include <stdio.h>
    int main (void) {
        printf ("Hello\n");
        return 0;
    }
    
    pax> gcc -o hello hello.c
    

    然后创建一个shell脚本testEmbed.sh,它会自行解码:

    pax> cat testEmbed.sh
    
    #!/bin/bash
    rm -f hello
    uudecode $0
    ./hello
    rm -f hello
    exit
    

    第一个rm 语句表明hello 可执行文件是由该脚本重新创建的,而不是在您的编译中徘徊。由于您还需要文件中的有效负载,请将编码的可执行文件附加到文件的末尾:

    pax> uuencode hello hello >>testEmbed.sh
    

    之后,当您执行脚本testEmbed.sh 时,它会提取可执行文件并运行它。

    之所以有效,是因为uudecode 在其输入中查找某些标记行(beginend),这些标记行由uuencode 放在那里,所以它只尝试解码编码的程序,而不是整个脚本:

    pax> cat testEmbed.sh
    
    #!/bin/bash
    rm -f hello
    uudecode $0
    ./hello
    rm -f hello
    exit
    
    begin 755 hello
    M?T5,1@$!`0````````````(``P`!````$(,$"#0```#`!@```````#0`(``'
    M`"@`'@`;``8````T````-(`$"#2`!`C@````X`````4````$`````P```!0!
    : : :
    M:&%N9&QE`%]?1%1/4E]%3D1?7P!?7VQI8F-?8W-U7VEN:70`7U]B<W-?<W1A
    M<G0`7V5N9`!P=71S0$!'3$E"0U\R+C``7V5D871A`%]?:38X-BYG971?<&-?
    4=&AU;FLN8G@`;6%I;@!?:6YI=```
    `
    end
    

    您可能还应该担心其他一些事情,例如您的程序可能需要目标系统上不存在的共享库,但上述过程基本上是您所需要的。


    JAR 文件的过程非常相似,只是运行它的方式不同。它仍然是一个文件,但您需要替换该行:

    ./hello
    

    带有能够运行 JAR 文件的东西,例如:

    java -jar hello.jar
    

    【讨论】:

    • 在 shell 脚本中添加 trap 'rm -f hello' SIGINT 也是一个好主意,以便在用户 Ctrl-C 的程序时清理临时文件。
    • 是的,我不怀疑您可以对该代码进行大量改进,并且一个很好的改进。我不想让它太复杂,因为我只是想理解这个概念。
    • 一个非常好的解释。谢谢
    • 当脚本内容作为文件(cp、ftp 等)四处移动时效果很好,但如果内容在机器之间剪切和粘贴,则通常不起作用。 uuencode 的默认编码具有您的 shell 可以尝试解释的字符/序列。例如,在 bash 中,uuencode 输出中的这一行: M9"TE2"TE32TE4RDN='AT"E!33TQ$/20H96-H;RD4%,Q*0I04S$](EM&lt;=2O(注意反引号单引号)会产生以下错误:“-bash: command替换:第 1 行:`D4%,Q*0I04S$](EM
    • 克里斯,在任何时候你都不应该处于 shell 试图解释 uuencode 输出的位置。它应该直接放入文件中, exit 之后,以确保shell 完全忽略它。如果您将其剪切并粘贴到交互式外壳而不是编辑器中,那么您做错了:-)
    【解决方案2】:

    我认为makeself 就是您所描述的。

    【讨论】:

    • makeself 是一个了不起的工具,感谢您提供此信息!
    【解决方案3】:

    执行此操作的可移植方法是使用 printf 命令和八进制转义:

    printf '\001\002\003'
    

    打印字节 1、2 和 3。由于您可能不想全部手动编写,因此可以使用 od -b 命令生成文件的八进制转储,然后您可以使用 @ 987654324@ 脚本去除垃圾并放置正确的反斜杠。

    【讨论】:

    • 用八进制创建字符串的命令是od -b BINARYFILE | sed -n 's%[0-9]\{4,\}\ \([0-9]\{3\}.*\)%\1%p' | perl -pe 's%^%\\%;s%\ %\\%g;s%\n%%')。这个创建的八进制字符串就是 printf 必须作为参数的那个。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-02-18
    • 2013-08-26
    • 2019-02-21
    • 2011-09-04
    • 1970-01-01
    • 2020-03-05
    相关资源
    最近更新 更多