Linux 自更新github中的bash脚本

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

我试图让我的脚本检查我在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 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”
低于1
ARGS=“($@)”
肯定应该是
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试图通过使用保护递归调用来避免这种情况