我正在开发一个脚本,它变得非常复杂,因此我想包含一个简单选项来将其更新为最新版本。这是我的方法:
set -o errexit
SELF=$(basename $0)
UPDATE_BASE=http://something
runSelfUpdate() {
echo "Performing self-update..."
# Download new version
wget --quiet --output-document=$0.tmp $UPDATE_BASE/$SELF
# Copy over modes from old version
OCTAL_MODE=$(stat -c '%a' $0)
chmod $OCTAL_MODE $0.tmp
# Overwrite old file with new
mv $0.tmp $0
exit 0
}
脚本似乎按预期工作,但我想知道这种方法是否存在任何注意事项。我很难相信一个脚本可以在没有后果的情况下覆盖自身。
更明确地说,我想知道 bash 是否会逐行读取并执行脚本,在mv
之后,exit 0
可能会变成新脚本中的其他内容。我记得 Windows 在处理.bat
文件时会像这样表现。
更新:我的原始代码片段没有包含set -o errexit
。据我了解,这应该可以保护我免受由wget
引起的问题。
此外,在这种情况下,UPDATE_BASE
指向版本控制下的位置(以缓解担忧)。
结果:根据这些答案的输入,我构建了这个修订后的方法:
runSelfUpdate() {
echo "Performing self-update..."
# Download new version
echo -n "Downloading latest version..."
if ! wget --quiet --output-document="$0.tmp" $UPDATE_BASE/$SELF ; then
echo "Failed: Error while trying to wget new version!"
echo "File requested: $UPDATE_BASE/$SELF"
exit 1
fi
echo "Done."
# Copy over modes from old version
OCTAL_MODE=$(stat -c '%a' $SELF)
if ! chmod $OCTAL_MODE "$0.tmp" ; then
echo "Failed: Error while trying to set mode on $0.tmp."
exit 1
fi
# Spawn update script
cat > updateScript.sh << EOF
#!/bin/bash
# Overwrite old file with new
if mv "$0.tmp" "$0"; then
echo "Done. Update complete."
rm \$0
else
echo "Failed!"
fi
EOF
echo -n "Inserting update process..."
exec /bin/bash updateScript.sh
}
exec "$0"
加上需要中继的任何参数(也许是:exec "$0" "$@"
)替换exit 0
不是更好吗?也就是说,在处理下载、验证和替换@shellter所讨论的脚本的前身的机制之后。 - Jonathan Lefflerstat -f'%A' $0
。 - Leon S.