Crack_David
Crack_David

Reputation: 2843

Re-directing a string containing a git command under double quotes fails

I am creating a bash script-file from an automated bash installation.

That file should only cd into a git directory, look for a new version and if there is one pull latest changes and rebuild.

The script itself works and the file gets created, but on creation it shows me fatal: not a git repository (or any of the parent directories): .git twice.

create_file.sh

echo "HOME=/home/nknx" > nknupdate
echo "GOPATH=/home/nknx/go" >> nknupdate
echo "PATH=/usr/local/go/bin:$PATH:$GOPATH/bin" >> nknupdate
echo "cd /home/nknx/go/src/github.com/nknorg/nkn" >> nknupdate
echo "git fetch &>/dev/null" >> nknupdate
echo "LOCAL=$(git rev-parse HEAD)" >> nknupdate
echo "UPSTREAM=$(git rev-parse @{u})" >> nknupdate
echo "if [ $LOCAL != $UPSTREAM ]" >> nknupdate
echo "then" >> nknupdate
echo "systemctl stop nkn.service;" >> nknupdate
echo "git merge;" >> nknupdate
echo "make deepclean;" >> nknupdate
echo "make;" >> nknupdate
echo "chown -R nknx:nknx /home/nknx/go;" >> nknupdate
echo "systemctl restart nkn.service;" >> nknupdate
echo "fi" >> nknupdate

I ran the script with bash -x create_file.sh:

 + echo HOME=/home/nknx
 + echo GOPATH=/home/nknx/go
 + echo PATH=/usr/local/go/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin:/bin
 + echo 'cd /home/nknx/go/src/github.com/nknorg/nkn'
 + echo 'git fetch &>/dev/null'
++ git rev-parse HEAD
fatal: not a git repository (or any of the parent directories): .git
 + echo LOCAL=
++ git rev-parse '@{u}'
fatal: not a git repository (or any of the parent directories): .git
 + echo UPSTREAM=
 + echo 'if [  !=  ]'
 + echo then
 + echo 'systemctl stop nkn.service;'
 + echo 'git merge;'
 + echo 'make deepclean;'
 + echo 'make;'
 + echo 'chown -R nknx:nknx /home/nknx/go;'
 + echo 'systemctl restart nkn.service;'
 + echo fi

Why does it throw this error when I am just creating a file? How can I get rid of it?

Upvotes: 2

Views: 119

Answers (2)

Inian
Inian

Reputation: 85653

As rightly pointed in the other answer, running in debug mode should have help you identify the problem.

The problem is with the command-substitution $(..) getting expanded inside ".." when writing the following commands to the file. The shell has run the commands in the current path instead of appending the command to the file nknupdate.

echo "LOCAL=$(git rev-parse HEAD)" >> nknupdate
echo "UPSTREAM=$(git rev-parse @{u})" >> nknupdate

The shell first tries to expand the quotes which would need to expand the command-substitution i.e. to run the git command. Since the path the script runs does not contain a .git directory, the above commands rendered a failure.

The way to solve this is to defer expanding the command-substitution, either by escaping it or putting it inside quotes. Either of the approaches should be fine.

echo 'PATH=/usr/local/go/bin:$PATH:$GOPATH/bin' >> nknupdate
echo 'LOCAL=$(git rev-parse HEAD)' >> nknupdate
echo 'UPSTREAM=$(git rev-parse @{u})' >> nknupdate
echo 'if [ $LOCAL != $UPSTREAM ]' >> nknupdate

So, any such lines containing a $ expansion, be it of variable expansion ($var) or a command-substitution $(..) should be escaped for the commands to be properly written to the file.

Upvotes: 4

glenn jackman
glenn jackman

Reputation: 246837

For creating a file, there are much more attractive methods than redirecting every single line. A here-document for example:

cat <<'END_CODE' > nkupdate
#!/usr/bin/env bash
set -e

HOME=/home/nknx
GOPATH=/home/nknx/go
PATH="/usr/local/go/bin:$PATH:$GOPATH/bin"
cd "$HOME/go/src/github.com/nknorg/nkn"
git fetch &>/dev/null
LOCAL=$(git rev-parse HEAD)
UPSTREAM=$(git rev-parse @{u})

if [ "$LOCAL" != "$UPSTREAM" ]
then
    systemctl stop nkn.service
    git merge
    make deepclean
    make
    chown -R nknx:nknx "$HOME/go"
    systemctl restart nkn.service
fi

END_CODE

The single quotes in <<'END_CODE' have the effect of single quoting the entire here-doc.

Upvotes: 3

Related Questions