我将如何制作可以在sh
上执行的自解压存档?
我最接近的是:
extract_archive () {
printf '<archive_contents>' | tar -C "$extract_dir" -xvf -
}
其中<archive_contents>
包含带有空字符的压缩包,%
、'
和字符转义并括在单引号之间。
有没有更好的方法来做到这一点,这样就不需要逃跑了?
(请不要指出我shar
,makeself
等。我想从头开始写它。
另一种变体是使用标记作为外壳脚本的结尾,并使用 sed 来剪切外壳脚本本身。
脚本selfextract.sh
:
#!/bin/bash
sed '0,/^#EOF#$/d' $0 | tar zx; exit 0
#EOF#
如何使用:
# create sfx
cat selfextract.sh data.tar.gz >example_sfx.sh
# unpack sfx
bash example_sfx.sh
由于 shell 脚本不是编译的,而是逐条语句执行的,因此您可以使用如下模式(未经测试)混合二进制和文本内容:
#!/bin/sh
sed -e '1,/^exit$/d' "$0" | tar -C "${1-.}" -zxvf -
exit
<binary tar gzipped content here>
您可以将这两行添加到几乎任何tar + gzip文件的顶部,以使其可自解压。
要测试:
$ 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
一些关于如何做到这一点的好文章可以在以下位置找到:
- http://www.linuxjournal.com/node/1005818。
- https://community.linuxmint.com/tutorial/view/1998
是的,您可以使用 xtar
本机执行此操作。
-
构建
xtar
elf64 tar 自解压器头(您可以自由修改它以支持 elf32、pe 和其他可执行格式),它基于轻量级的 bsdtar untar 和 std elf lib。cc contrib/xtar.c -o ./xtar
-
将二进制
xtar
复制到yourTar.xtar
cp ./xtar yourTar.xtar
-
将
yourTar.tar
存档附加到yourTar.xtar
末尾cat yourTar.tar >> yourTar.xtar chmod +x yourTar.xtar
这是一个dash
脚本(应该在 Linux 和 Mac OS-es 上开箱即用),可以创建自解压的 shell 存档(您可以使用 --help
标志调用它以了解如何使用它):
#!/bin/dash
ExtractFirstAndLastPathComponent () {
eval current_path=""$$1""
first_path_component=""
last_path_component=""
if [ -n "$current_path" ]; then
#Remove trailing '/':
temp="${current_path%?}"
while [ "${current_path#"$temp"}" = "/" ]; do
current_path="${current_path%?}"
temp="${current_path%?}"
done
first_path_component="${current_path%"/"*}"
if [ -z "$first_path_component" ]; then
last_path_component="${current_path#'/'}"
else
last_path_component="${current_path#"$first_path_component""/"}"
fi
fi
eval $2=""$first_path_component""
eval $3=""$last_path_component""
}
ConvertToFullPath () {
initial_dir_ctfp="$PWD"
eval current_path=""$$1""
lpc_current_path=""
ExtractFirstAndLastPathComponent current_path fpc_current_path lpc_current_path
if [ -n "$fpc_current_path" ]; then
if [ -d "$fpc_current_path" ]; then
cd "$fpc_current_path"
fpc_current_path="$PWD"
fi
fi
if [ -n "$lpc_current_path" ]; then
eval $2=""$fpc_current_path/$lpc_current_path""
else
eval $2="/"
fi
cd "$initial_dir_ctfp"
}
GetFileEncodingAndSizeInBytes () {
eval file_to_test="$$1"
GetFileSizeInBytes file_to_test file_to_test_size_in_bytes
#Get file mime encoding:
if [ -d "$file_to_test" ]; then
result="directory"
file_to_test_size_in_bytes="0"
elif [ ! "$file_to_test_size_in_bytes" -eq "0" ]; then
file_mime_type="$(file -bL --mime-encoding "$file_to_test" 2>/dev/null)" || { file_mime_type="undetermined"; }
case "$file_mime_type" in
*"binary"* )
#Only binary files containing the NULL character (^@) are considered binaries in this script:
(cat -v "$file_to_test" | sed "/^@/i'^@'$NL2") | { grep -q "^@"; } && result="binary" || result="ascii"
;;
*"ascii"* )
result="ascii"
;;
*"utf"* )
result="${file_mime_type##*" "}"
;;
* )
result="undetermined"
;;
esac
else
result="ascii"
fi
eval $2="$result"
eval $3="$file_to_test_size_in_bytes"
}
GetOSType () {
case "$(uname -s)" in
*"Darwin"* | *"BSD"* )
eval $1="BSD-based"
;;
*"Linux"* )
eval $1="Linux"
;;
* )
eval $1="Other"
;;
esac
}
GetFileSizeInBytes () {
eval file=""$$1""
[ -z "$OS_TYPE" ] && GetOSType OS_TYPE
if [ "$OS_TYPE" = "BSD-based" ]; then
file_size_in_bytes="$(stat -Lf %z -- "$file")" 2>/dev/null || { file_size_in_bytes="-1"; }
elif [ "$OS_TYPE" = "Linux" ] || [ "$OS_TYPE" = "Other" ]; then
file_size_in_bytes="$(stat -c %s -- "$file")" 2>/dev/null || { file_size_in_bytes="-1"; }
fi
eval $2="$file_size_in_bytes"
}
PrintErrorExtra () {
{
if [ ! "$error" = "true" ]; then
for cc in $(seq 1 $params_0); do
eval current_param_func="$params_$cc"
printf 'n%sn' "Parameter $cc: '$current_param_func'"
done
if [ -n "$find_parameters" ]; then
printf 'n%snn' "Find parameters: $find_parameters"
fi
fi
}>&2
}
PrintInTitle () {
printf "