Linux 自更新github中的bash脚本
我试图让我的脚本检查我在github中的repo是否有更新,然后获取更新并用新代码替换旧代码,并运行新代码“而不是旧代码”。我想出了这个,但它完成后会更新Linux 自更新github中的bash脚本,linux,bash,git,github,self-updating,Linux,Bash,Git,Github,Self Updating,我试图让我的脚本检查我在github中的repo是否有更新,然后获取更新并用新代码替换旧代码,并运行新代码“而不是旧代码”。我想出了这个,但它完成后会更新 self_update() { cd $(dirname $0) git fetch > a.txt 1> /dev/null 2> /dev/null git reset --hard >> a.txt 1> /dev/null 2> /dev/null git pu
self_update() {
cd $(dirname $0)
git fetch > a.txt 1> /dev/null 2> /dev/null
git reset --hard >> a.txt 1> /dev/null 2> /dev/null
git pull >> a.txt 1> /dev/null 2> /dev/null
rm a.txt
chmod +x "$(basename $0)"
cd -
}
self_update
echo “some code”
编辑:我在这里找到了下面的代码,它更新了我的脚本。然而,它进入一个循环,从不运行新的或旧的代码,不知道为什么
#!/bin/bash
SCRIPT=$(readlink -f "$0")
SCRIPTPATH=$(dirname "$SCRIPT")
SCRIPTNAME="$0"
ARGS="( $@ )"
BRANCH="master"
self_update() {
cd $SCRIPTPATH
git fetch
[ -n $(git diff --name-only origin/$BRANCH | grep $SCRIPTNAME) ] && {
echo "Found a new version of me, updating myself..."
git pull --force
git checkout $BRANCH
git pull --force
echo "Running the new version..."
exec "$SCRIPTNAME" "${ARGS[@]}"
# Now exit this old instance
exit 1
}
echo "Already the latest version."
}
self_update
echo “some code”
重复输出:
Found a new version of me, updating myself...
HEAD is now at 5dd5111 Update tool
Already up to date
Already on ‘master’
Your branch is up to date with origin/master
直到i CTRL-C,它才停止打印输出
输出:使用:bash-x/opt/script/firstScript-h执行
++ readlink -f /opt/script/firstScript
+ SCRIPT=/opt/script/firstScript
++ dirname /opt/script/firstScript
+ SCRIPTPATH=/opt/script
+ SCRIPTNAME=/opt/script/firstScript
+ ARGS='( -h )'
+ BRANCH=master
+ self_update
+ cd /opt/script
+ git fetch
++ git diff --name-only origin/master
++ grep /opt/script/firstScript
+ '[' -n ']'
+ echo 'Found a new version of me, updating myself...'
Found a new version of me, updating myself...
+ git pull --force
Already up to date.
+ git checkout master
Already on 'master'
Your branch is up to date with 'origin/master'.
+ git pull --force
Already up to date.
+ echo 'Running the new version...'
Running the new version...
+ exec bash -x /opt/script/firstScript '( -h )'
++ readlink -f /opt/script/firstScript
+ SCRIPT=/opt/script/firstScript
++ dirname /opt/script/firstScript
+ SCRIPTPATH=/opt/script
+ SCRIPTNAME=/opt/script/firstScript
+ ARGS='( ( -h ) )'
+ BRANCH=master
+ self_update
+ cd /opt/script
+ git fetch
++ git diff --name-only origin/master
++ grep /opt/script/firstScript
+ '[' -n ']'
+ echo 'Found a new version of me, updating myself...'
Found a new version of me, updating myself...
+ git pull --force
Already up to date.
+ git checkout master
Already on 'master'
Your branch is up to date with 'origin/master'.
+ git pull --force
Already up to date.
+ echo 'Running the new version...'
Running the new version...
+ exec bash -x /opt/script/firstScript '( ( -h ) )'
++ readlink -f /opt/script/firstScript
+ SCRIPT=/opt/script/firstScript
++ dirname /opt/script/firstScript
+ SCRIPTPATH=/opt/script
+ SCRIPTNAME=/opt/script/firstScript
+ ARGS='( ( ( -h ) ) )'
+ BRANCH=master
+ self_update
+ cd /opt/script
+ git fetch
++ git diff --name-only origin/master
++ grep /opt/script/firstScript
+ '[' -n ']'
+ echo 'Found a new version of me, updating myself...'
Found a new version of me, updating myself...
+ git pull --force
Already up to date.
+ git checkout master
Already on 'master'
Your branch is up to date with 'origin/master'.
+ git pull --force
^C
Found a new version of me, updating myself...
Already up to date.
Your branch is up to date with 'origin/master'.
Already up to date.
Running the new version...
Found a new version of me, updating myself...
Already up to date.
Your branch is up to date with 'origin/master'.
Already up to date.
Running the new version...
Found a new version of me, updating myself...
Already up to date.
Your branch is up to date with 'origin/master'.
Already up to date.
Running the new version...
Found a new version of me, updating myself...
Already up to date.
Your branch is up to date with 'origin/master'.
Already up to date.
Running the new version...
Found a new version of me, updating myself...
Already up to date.
Your branch is up to date with 'origin/master'.
Already up to date.
Running the new version...
Found a new version of me, updating myself...
Already up to date.
Your branch is up to date with 'origin/master'.
Already up to date.
Running the new version...
Found a new version of me, updating myself...
Already up to date.
Your branch is up to date with 'origin/master'.
Already up to date.
Running the new version...
Found a new version of me, updating myself...
^C
输出:使用:bash/opt/script/firstScript-h执行
++ readlink -f /opt/script/firstScript
+ SCRIPT=/opt/script/firstScript
++ dirname /opt/script/firstScript
+ SCRIPTPATH=/opt/script
+ SCRIPTNAME=/opt/script/firstScript
+ ARGS='( -h )'
+ BRANCH=master
+ self_update
+ cd /opt/script
+ git fetch
++ git diff --name-only origin/master
++ grep /opt/script/firstScript
+ '[' -n ']'
+ echo 'Found a new version of me, updating myself...'
Found a new version of me, updating myself...
+ git pull --force
Already up to date.
+ git checkout master
Already on 'master'
Your branch is up to date with 'origin/master'.
+ git pull --force
Already up to date.
+ echo 'Running the new version...'
Running the new version...
+ exec bash -x /opt/script/firstScript '( -h )'
++ readlink -f /opt/script/firstScript
+ SCRIPT=/opt/script/firstScript
++ dirname /opt/script/firstScript
+ SCRIPTPATH=/opt/script
+ SCRIPTNAME=/opt/script/firstScript
+ ARGS='( ( -h ) )'
+ BRANCH=master
+ self_update
+ cd /opt/script
+ git fetch
++ git diff --name-only origin/master
++ grep /opt/script/firstScript
+ '[' -n ']'
+ echo 'Found a new version of me, updating myself...'
Found a new version of me, updating myself...
+ git pull --force
Already up to date.
+ git checkout master
Already on 'master'
Your branch is up to date with 'origin/master'.
+ git pull --force
Already up to date.
+ echo 'Running the new version...'
Running the new version...
+ exec bash -x /opt/script/firstScript '( ( -h ) )'
++ readlink -f /opt/script/firstScript
+ SCRIPT=/opt/script/firstScript
++ dirname /opt/script/firstScript
+ SCRIPTPATH=/opt/script
+ SCRIPTNAME=/opt/script/firstScript
+ ARGS='( ( ( -h ) ) )'
+ BRANCH=master
+ self_update
+ cd /opt/script
+ git fetch
++ git diff --name-only origin/master
++ grep /opt/script/firstScript
+ '[' -n ']'
+ echo 'Found a new version of me, updating myself...'
Found a new version of me, updating myself...
+ git pull --force
Already up to date.
+ git checkout master
Already on 'master'
Your branch is up to date with 'origin/master'.
+ git pull --force
^C
Found a new version of me, updating myself...
Already up to date.
Your branch is up to date with 'origin/master'.
Already up to date.
Running the new version...
Found a new version of me, updating myself...
Already up to date.
Your branch is up to date with 'origin/master'.
Already up to date.
Running the new version...
Found a new version of me, updating myself...
Already up to date.
Your branch is up to date with 'origin/master'.
Already up to date.
Running the new version...
Found a new version of me, updating myself...
Already up to date.
Your branch is up to date with 'origin/master'.
Already up to date.
Running the new version...
Found a new version of me, updating myself...
Already up to date.
Your branch is up to date with 'origin/master'.
Already up to date.
Running the new version...
Found a new version of me, updating myself...
Already up to date.
Your branch is up to date with 'origin/master'.
Already up to date.
Running the new version...
Found a new version of me, updating myself...
Already up to date.
Your branch is up to date with 'origin/master'.
Already up to date.
Running the new version...
Found a new version of me, updating myself...
^C
脚本启动“self_update”bash函数,该函数本身调用
exec“$SCRIPTNAME”“${ARGS[@]}”
。
但是如果我读得好的话,$SCRIPTNAME
就是你的脚本
您的脚本将继续递归地调用自己。
这就是为什么你在循环
你有没有考虑过用类似的东西来运行你的脚本,而不是让它自己调用
编辑:
另外,测试中的git命令,
git diff--name only origin/$BRANCH
将在包含脚本文件的行中做出响应(如果您在其中进行了本地更改),并将永远循环。脚本无法自我更新可能有多种原因。撇开“为什么”一分钟,考虑使用一个基于环境变量的“双重调用”保护。它将防止重复尝试更新
self_update() {
[ "$UPDATE_GUARD" ] && return
export UPDATE_GUARD=YES
cd $SCRIPTPATH
git fetch
[ -n $(git diff --name-only origin/$BRANCH | grep $SCRIPTNAME) ] && {
echo "Found a new version of me, updating myself..."
git pull --force
git checkout $BRANCH
git pull --force
echo "Running the new version..."
exec "$SCRIPTNAME" "${ARGS[@]}"
# Now exit this old instance
exit 1
}
echo "Already the latest version."
}
也可以考虑更改<代码> SelfUpUptudio返回到原始CWD,如果它可能对运行脚本产生影响。
< P>我怀疑您还没有为当前分支设置上游跟踪。然后,git fetch
什么也不做。试一试
git fetch origin master
相反(假设这是您想要的上游和分支)
您似乎也不理解找到的代码中exec
的重要性。这将用更新的版本替换当前正在执行的脚本,并从一开始就开始运行它。那是不可能的
update_code
echo "some stuff"
将在更新自身后立即回显“一些东西”
。取而代之的是,它将再次执行自己,希望这次能使用更新版本的代码
但是,
[ -n $(git diff --name-only origin/$BRANCH | grep $SCRIPTNAME) ]
这是一个非常迂回且可能脆弱的结构。您正在询问grep
是否返回了任何(非空)输出。。。但是很明显,grep
本身就是一个检查是否有匹配项的工具。此外,在这里使用SCRIPTNAME
是很脆弱的——如果使用/home/you/work/script/update\u self\u test
这样的路径调用脚本,这就是SCRIPTNAME
所包含的内容,但是git diff
将只输出相对路径(script/update\u self\u test
在本例中,如果/home/you/work
是Git工作目录),因此grep
将失败。(在bash-x
成绩单中,您可以看到grep/opt/script/firstScript
——这正是这个bug。)
既然您已经在文件的目录中,我建议
git diff --name-only origin/master "$(basename "$SCRIPTNAME")"
如果文件未更改,则不会打印任何内容,如果文件已更改,则不会打印单个文件的文件名。遗憾的是,这不会设置其退出代码以指示成功或失败(我想在这里很难定义,尽管传统的惯例是常规的diff
命令在存在差异时报告非零退出代码),但我们可以使用
git diff --name-only origin/master "$(basename "$SCRIPTNAME")" | grep -q . &&
适用于所有条件。(另请注意)
最后,您自己的尝试也有另一个问题。除了未能执行exec
,您还有模糊的重定向。您试图将内容发送到文件a.txt
,但您也试图将相同的内容发送到/dev/null
。到底是什么?请下决心
不管它值多少钱
echo testing >a.txt 1>/dev/null
将测试
发送到/dev/null
;它首先将标准输出重定向到a.txt
,然后更新重定向,因此,如果a.txt
中不存在,您只需在其中创建一个空文件即可
最后,您可能还应该将私有变量转换为小写;但我发现您只是从另一个答案复制了错误的约定。在阅读bash-x输出后,我可以给您重写脚本
#!/bin/bash
# Here I remark changes
SCRIPT="$(readlink -f "$0")"
SCRIPTFILE="$(basename "$SCRIPT")" # get name of the file (not full path)
SCRIPTPATH="$(dirname "$SCRIPT")"
SCRIPTNAME="$0"
ARGS=( "$@" ) # fixed to make array of args (see below)
BRANCH="master"
self_update() {
cd "$SCRIPTPATH"
git fetch
# in the next line
# 1. added double-quotes (see below)
# 2. removed grep expression so
# git-diff will check only script
# file
[ -n "$(git diff --name-only "origin/$BRANCH" "$SCRIPTFILE")" ] && {
echo "Found a new version of me, updating myself..."
git pull --force
git checkout "$BRANCH"
git pull --force
echo "Running the new version..."
cd - # return to original working dir
exec "$SCRIPTNAME" "${ARGS[@]}"
# Now exit this old instance
exit 1
}
echo "Already the latest version."
}
self_update
echo “some code”
低于1ARGS=“($@)”
肯定应该是ARGS=(“$@”)
,否则在使用(-h)
参数而不是-h
执行更新脚本后(通常,它是在所有参数连接在一个字符串中的情况下执行的,也就是说,您以/opt/script/firstScript-a-b-c
的形式运行它,更新后它以/opt/script/firstScript'(-a-b-c)
的形式运行。)
低于2。在
$(…)
周围必须使用双引号,否则[-n
使用]
作为输入参数,并返回true,因为它不是空的(而[-n
的参数列表中忽略了git diff | grep
的空输出)(这是循环原因)如果手动运行,在执行了pull
之后,git diff--name only origin/$BRANCH | grep$SCRIPTNAME
命令,您会得到任何输出吗?我添加了输出,请检查它。您只添加了脚本的输出,而不是我要求的。如果我执行git fetch;git reset--hard;git pull;手动。然后,git diff--name-只有origin/$BRANCH | grep$SCRIPTNAME不会打印我的脚本名,但如果我不手动打印,它将输出我的脚本名,并使其进入循环。所以问题是git命令。也许比我有更多git经验的人现在可以看到发生了什么。为了测试,我会放置一个git diff--name only origin/$BRANCHH
在脚本中的if
之前,并将输出添加到问题中。我也认为这是原因,但OP试图通过使用