自解压tar压缩包(shell脚本)

sqxo8psd  于 11个月前  发布在  Shell
关注(0)|答案(3)|浏览(110)

我试图写一个shell脚本,创建另一个自解压的tar存档,压缩和编码在base64。我不知道从这里去哪里,几乎没有shell脚本的经验。
因为这个脚本创建了压缩和编码的tar存档,但是当我试图从终端运行./tarName时,自解压不起作用。

#!/bin/sh
tarName=$1;

if [ -e $tarName.tar.gz ] 

    then /bin/echo "$tarName already exists" 
    exit 0
fi

shift;
for files;
do
    tar -czvf tmpTarBall.tar.gz $files;
done

echo "#!/bin/sh" >> $tarName.tar.gz;
echo "base64 -d $tarName.tar.gz"  >> $tarName.tar.gz;
echo "tar -xzvf $tarName.tar.gz" >> $tarName.tar.gz;
chmod +x ./$tarName.tar.gz;

base64 tmpTarBall.tar.gz >> $tarName.tar.gz;
rm tmpTarBall.tar.gz;

字符串
----------更新
做了一些环顾四周,这是我现在有,仍然不工作。有人能解释给我为什么?

#!/bin/sh
tarName=$1;

if [ -e $tarName.tar.gz ] 

    then /bin/echo "$tarName already exists" 
    exit 0
fi

shift;
for files;
do
    tar -czvf tmpTarBall.tar.gz $files;
done

cat > extract.sh;
echo "#!/bin/sh" >> extract.sh;
echo "sed '0,/^#TARBALL#$/d' $0 | $tarName.tar.gz | base64 -d | tar -xzv; exit 0" >> extract.sh;
echo "#TARBALL#" >> extract.sh;

cat extract.sh tmpTarBall.tar.gz > $tarName.tar.gz;
chmod +x ./$tarName.tar.gz;

rm extract.sh tmpTarBall.tar.gz;


当我尝试运行tarName.tar.gz时,我得到错误:./tarName.tar.gz:2:./tarName. tar.gz:tarName.tar.gz:not found gzip:stdin:unexpected end of file tar:Child returned status 1 tar:Error is not recoverable:exiting now

nzrxty8p

nzrxty8p1#

期望输出

概括地说,您要生成的脚本应该如下所示:

base64 -d <<'EOF' | tar -xzf -
…base-64 encoded data…
EOF

字符串
base64命令解码它的标准输入,它作为一个here文档提供,以一个只包含EOF的行结束。输出被写入tar,并带有从标准输入中提取gzip数据的选项。

最小脚本

所以,一个最小的生成器脚本看起来像这样:

echo "base64 -d <<'EOF' | tar -czf -"
tar -czf - "$@" | base64 -w 72
echo "EOF"


这将重复base64 … | tar …行,然后使用tar在标准输出上生成一个压缩的tar文件,其中包含命令行上指定的文件或目录,输出通过管道传输到GNU coreutils版本的base64,并带有指定输出行宽度为72个字符的选项(加上新行)。这后面都跟有EOF来标记here文档的结束。
你可以在两个脚本中的任何一个中添加shebang行(#!/bin/sh)。不需要选择一个更具体的shell;这只使用了可以追溯到过去的核心shell脚本结构-在POSIX在任何人眼中都是一线生机之前。

可能的并发症

可能的复杂性包括对Mac OS X base64的支持,其使用信息如下:

Usage:  base64 [-dhvD] [-b num] [-i in_file] [-o out_file]
  -h, --help     display this message
  -D, --decode   decodes input
  -b, --break    break encoded string into num character lines
  -i, --input    input file (default: "-" for stdin)
  -o, --output   output file (default: "-" for stdout)


-v选项和-d选项都生成base64: invalid option -- v(对应于相应的字母),以及用法。似乎没有办法从中获取版本信息。然而,当您请求base64 --version时,GNU的base64确实会生成一条有用的消息。标准输出的第一行将包含如下内容:

base64 (GNU coreutils) 8.22
Copyright (C) 2013 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

Written by Simon Josefsson.


这是写入标准输出的。所以,你可以自动检测你是否有GNU base64并相应地调整。你需要在生成器脚本中有一个测试,并在生成的脚本中有一个测试的副本。这绝对是一个更精致的程序。

vshtjzan

vshtjzan2#

有必要自己做这件事吗?有一个名为makeself的现有工具可以为你做这件事。如果你需要自己写这件事,这里有一些想法:
您的输出文件是一个归档文件,其前面粘有一个shell脚本。提取过程通过base64tar运行 * 整个 * 输出文件,而不仅仅是归档文件。base64调用将脚本部分变成垃圾,然后混淆tar。您需要做的是添加一些代码,将脚本与归档文件分开,然后只在归档文件部分运行其余的命令。一种可能的方法是调整提取脚本,如下所示:

#!/bin/sh
linenum=$(grep -n "__END_OF_SCRIPT_MARKER__" $tarName.tar.gz | tail -1 | sed -e 's/:.*//')
tail -n +$(($linenum + 1)) $tarName.tar.gz | base64 -d | tar -xzv
exit 0
__END_OF_SCRIPT_MARKER__

字符串
确保在标记文本之后的脚本部分中除了换行符之外没有任何内容(这个网站上的标记并不显示)。这样,您就可以使用grep来查找包含标记的行号,然后使用tail剥离这些行号。剩下的将是存档部分,这是正常处理的其余代码。exit行确保 shell 不试图执行标记文本或存档内容作为代码。您可以保持提取代码在一个较低的压缩格式,如果你愿意,但是你最终不得不为存档部分创建一个临时文件,并确保它被删除。

z4bn682m

z4bn682m3#

有一种方法可以不使用base64编码。
你可以在文件前面加上一个小的头,当运行时,它会从文件中剥离出来,并将其传递给tar。这个选项使文件比base64做同样的事情更小。我也认为这个选项更符合压缩的精神。
这是我能做的最好的,并且仍然可以正常运行:

dd if=$0 bs=4 skip=13 2>/dev/null | tar xavf -
exit
...raw tar file...

字符串
如果你愿意,你可以在开始时加入shebang。

#!/bin/sh
dd if=$0 bs=2 skip=31 2>/dev/null | tar xavf -
exit
...raw tar file...


作为参考,-a选项用于压缩自动检测。
要实际使用该代码段,请运行以下命令

cat headerfile data.tar.gz > data.tar.gz.self


不过这种方法有一些复杂之处,即固定的跳过值。除非头部本身发生变化,否则它不会引起问题。
如果你决定改变头脚本,你可以得到新的大小的头文件和编辑跳过选项使用dd。

相关问题