3
\$\begingroup\$

It's a simple bash script but I'm hoping for feedback, advice and examples on how to improve the script and code. Can you guide me how to put more checks in the code and more if possible?

This code:

  • Sets IFS variable and backs it up
  • Sets a trap for signals that can kill the script and a trap for exit to do run a cleanup function.
  • Then it pushes changes from the local TO the remote repository
  • Then it syncs the local copy FROM the repository/fork
  • Then there is code to update the Fork from the original but that will be used later on other repositories.
  • Then it gives control back to these signals SIGINT SIGQUIT SIGTERM
  • Then it's set to send a email with the result/status of what's been run after theexit

#!/usr/bin/env bash

IFS_OLD=$IFS
IFS=$'\n\t'

cleanup ()
{
    if [ -n "$1" ]; then
        echo "Aborted by $1"
    elif [ $status -ne 0 ]; then
        echo "Failure (status $status)"
    else
        echo "Success"
        IFS=$IFS_OLD
        #cd "$HOME" || { echo "cd $HOME failed"; exit 155; }
    fi
}
trap 'status=$?; cleanup; exit $status' EXIT
trap 'trap - HUP; cleanup SIGHUP; kill -HUP $$' HUP
############################################################################ Sync the local TO the remote ##########################################
#{
#{    #...part of script with redirection...
#} > file1 2>file2 # ...and others as appropriate...
cd /home/kristjan/gitRepo_May2019/ || { echo "Failed to cd to /home/kristjan/gitRepo_May2019/!!!!!!!!"; exit 155; }
git add -A || { echo "Failed to git add -A: Sync the local TO the remote!!!!!!!!"; exit 155; } | 
if ! `grep -r up-to-date`
then
    git commit -m 'One small commit for man, one giant leap for melted MacBooks, UNIX and Linux are the best!!!!!!!!!!!!!!!!!!!!!!!!!' || { echo "Failed to git commit -m '......': Sync the local TO the remote!!!!!!!!"; exit 155; }

    git push -u origin master || { echo "Failed to git push -u origin master: Sync the local TO remote!!!!!!!!"; exit 155; }
fi

##################################################################333#3# Sync the local copy FROM the original repository/fork(github) ####################################
#git remote add upstream https://github.com/ORIGINAL_OWNER/ORIGINAL_REPOSITORY.git
#git remote add upstream https://github.com/somethingSomething78/C_Programming.git || { echo "Failed to git remote add upstream ........https://....: sync local copy FROM repo!!!!!!!!"; exit 155; }
#cd gitRepo_May2019/ || { echo "Failed to cd to the install directory!!!!!!!!"; exit 155; }
#sleep 2
git fetch upstream || { echo "Failed to fetch upstream: sync local copy FROM repo!!!!!!!!"; exit 155; }

git checkout master || { echo "Failed to git checkout master: sync local copy FROM repo!!!!!!!!"; exit 155; }

git merge upstream/master || { echo "Failed to git merge upstream/master: sync local copy FROM repo!!!!!!!!"; exit 155; }
####################################################################### Sync the remote fork with the ORIGINAL repository(github) 
# Setting and configuring under a new filename and for other repo's
#git clone git@github.com:YOUR-USERNAME/YOUR-FORKED-REPO.git
#cd into/cloned/fork-repo
#git remote add upstream git://github.com/ORIGINAL-DEV-USERNAME/REPO-YOU-FORKED-FROM.git
#git fetch upstream
#git pull upstream master


echo "Finished syncing system and remotes!"
sleep 2
############ Give control back to these signals
trap SIGINT SIGQUIT SIGTERM
############################

#} > file1 2>file2 # ...and others as appropriate...

exit 0

This is my .git/config for connecting to the servers with ssh keys (you could notice that origin and upstream are the same but that's because this git is not a fork but my personal private repo, this code will come to much better use when I setup syncing my forks):

 [core]
     repositoryformatversion = 0
     filemode = true
     bare = false
     logallrefupdates = true
 [remote "origin"]
     url = ssh://C_Programming:somethingSomething78/C_Programming.git
     fetch = +refs/heads/*:refs/remotes/origin/*
 [branch "master"]
     remote = origin
     merge = refs/heads/master
 [remote "upstream"]
     url = ssh://C_Programming/somethingSomething78/C_Programming.git
     fetch = +refs/heads/*:refs/remotes/upstream/*

I also had to setup ssh key for this particular repo and I have edited my .ssh/config file like this:

Host C_Programming
    HostName github.com
    User git
    IdentityFile ~/.ssh/id_rsa-GITHUBSCRIPT

Here I am testing the script:

[08:58:57][kristjan] ~ ~↓↓$↓↓ ./gitRepo_May2019.sh | mail -s "Github SYNC System Report: `hostname`" somethingSomething@mail.com
Already on 'master'

This is the mail it sent afterwards:

> Github SYNC System Report: Kundrum Hallur Kristjan Stefansson
> <somethingSomething@mail.com>      09:00 (3 hours ago)     
> Your branch is
> up-to-date with 'origin/master'.

> Already up-to-date. 

> Finished syncing system and remotes!

> Success

I put it in a cron(crontab -e) on my Debian Stretch 9.9 system:

21 00 * * 7 /bin/bash /home/kristjan/gitRepo_May2019.sh | mail -s "Github SYNC System Report: `hostname`" somethingSomething@mail.com

Here are other questions on this site with code for the same or similar purpose:

Rust GitHub repository downloader

Clone GitHub repository using Python

Python script to synchronise your locally cloned fork to its parent github repository

\$\endgroup\$
2
\$\begingroup\$

There's no need to reinstate the initial value of IFS because there's nowhere for the new value to propogate. When your script exits, the new value just ceases to exist. Same goes for the signal handlers.

On that note, why set IFS at all? I can't see any place that it has an effect.

Prefer [[ … ]] over [ … ] for tests (detailed explanation).

When testing for zero, consider an arithmetic test (( … )): it returns true for non-zero and false for zero, and doesn't require $ in front of ordinary variable names (specials like $* or $# still need the dollar sign).

For example, cleanup() might be rewritten:

cleanup() { 
  (( $# )) && echo "Aborted by $1" && return
  (( status )) && echo "Failure (status $status)" && return $status
  echo "Success"
}

cd /home/kristjan/gitRepo_May2019/ || { echo "Failed to cd to /home/kristjan/gitRepo_May2019/!!!!!!!!"; exit 155; }

This is a common pattern that can benefit from the use of a function:

 die()  { echo "$2"; exit $1; }

 cd $dir || die 155 "Failed to cd to $dir" 

Alternatively, the command's error output is usually good enough:

 cd $dir || exit 155 

Or, since you're checking basically everything for error exit, put set -e at the top of the script to make any error fatal.


if ! `grep -r up-to-date`

Don't use backticks here, recursively grepping STDIN doesn't make any sense, and grep's -w switch is probably appropriate:

 if ! grep -w up-to-date
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.