Git Hooks. How to read variables from user input? - bash

I'm trying to create a pre-commit hook. And I want it to interract with user. So, I've found that I can use
read -p "Enter info: " info
Or just
read info
I created a file:
pre-commit:
#!/bin/sh
read -r input
echo $input
It just should read variable and output it. But it doesn't work. I mean it doesn't work as hook. If I run it using terminal with ./.githooks/pre-commit, everything is okay. But when I use git commit -am "Hook", it echos empty string and doesn't read anything. Am I doing something wrong?
Git version is 2.28.0.windows.1

As in this gist, you might need to take into account stderr (used by Git commands, as for instance here)
#!/bin/sh
# Redirect output to stderr.
exec 1>&2
# enable user input
exec < /dev/tty
Example of a script following those lines:
consoleregexp='console.log'
# CHECK
if test $(git diff --cached | grep $consoleregexp | wc -l) != 0
then
exec git diff --cached | grep -ne $consoleregexp
read -p "There are some occurrences of console.log at your modification. Are you sure want to continue? (y/n)" yn
echo $yn | grep ^[Yy]$
if [ $? -eq 0 ]
then
exit 0; #THE USER WANTS TO CONTINUE
else
exit 1; # THE USER DONT WANT TO CONTINUE SO ROLLBACK
fi
fi

Related

How to change name of file if already present on remote machine?

I want to change the name of a file if it is already present on a remote server via SSH.
I tried this from here (SuperUser)
bash
ssh user#localhost -p 2222 'test -f /absolute/path/to/file' && echo 'YES' || echo 'NO'
This works well with a prompt, echoes YES when the file exists and NO when it doesn't. But I want this to be launched from a crontab, then it must be in a script.
Let's assume the file is called data.csv, a condition is set in a loop such as if there already is a data.csv file on the server, the file will be renamed data_1.csv and then data_2.csv, ... until the name is unique.
The renaming part works, but the detection part doesn't :
while [[ $fileIsPresent!='false' ]]
do
((appended+=1))
newFileName=${fileName}_${appended}.csv
remoteFilePathname=${remoteFolder}${newFileName}
ssh pi#localhost -p 2222 'test -f $remoteFilePathname' && fileIsPresent='true' || fileIsPresent='false'
done
always returns fileIsPresent='true' for any data_X.csv. All the paths are absolute.
Do you have any idea to help me?
This works:
$ cat replace.sh
#!/usr/bin/env bash
if [[ "$1" == "" ]]
then
echo "No filename passed."
exit
fi
if [[ ! -e "$1" ]]
then
echo "no such file"
exit
fi
base=${1%%.*} # get basename
ext=${1#*.} # get extension
for i in $(seq 1 100)
do
new="${base}_${i}.${ext}"
if [[ -e "$new" ]]
then
continue
fi
mv $1 $new
exit
done
$ ./replace.sh sample.csv
no such file
$ touch sample.csv
$ ./replace.sh sample.csv
$ ls
replace.sh
sample_1.csv
$ touch sample.csv
$ ./replace.sh sample.csv
$ ls
replace.sh
sample_1.csv
sample_2.csv
However, personally I'd prefer to use a timestamp instead of a number. Note that this sample will run out of names after 100. Timestamps won't. Something like $(date +%Y%m%d_%H%M%S).
As you asked for ideas to help you, I thought it worth mentioning that you probably don't want to start up to 100 ssh processes each one logging into the remote machine, so you might do better with a construct like this that only establishes a single ssh session that runs till complete:
ssh USER#REMOTE <<'EOF'
for ((i=0;i<10;i++)) ; do
echo $i
done
EOF
Alternatively, you can create and test a bash script locally and then run it remotely like this:
ssh USER#REMOTE 'bash -s' < LocallyTestedScript.bash

Writing to a file multiple times with Bash

I am creating a bash script to automate some commands and I am having some trouble writing my error checking to the same file.
#!/bin/bash
touch ErrorLog.txt
bro-cut service < conn.log | sort | uniq -c > ProtocolHierarchy.txt
if [ $? -eq 0 ]; then
echo -e "OK Protocol Hierarchy Created\n" > ErrorLog.txt
else
echo -e "FAILED Creating Protocol Hierarchy\n" > ErrorLog.txt
fi
bro-cut id.orig_h < dns.log | sort | uniq -c > AllIPAddresses.txt
if [ $? -eq 0 ]; then
echo -e "OK Created all IP Addresses\n" > ErrorLog.txt
else
echo -e "FAILED Creating all IP Addresses\n" > ErrorLog.txt
fi
The goal being to have a file I can open and see that all the commands worked or failed, currently the file looks like this
-e OK Created all IP Addresses
When I would like it to look like this
OK Protocol Hierarchy Created
OK Created all IP Addresses
I am really new to bash scripting so any tips would be greatly appreciated!
Open it once, and write to that file descriptor multiple times.
# Open (creating or truncating) the output file (only once!)
exec 3>ErrorLog.txt
# Write a line to that already-open file
echo "something" >&3
# Write a second line to that already-open file
echo "something else" >&3
# Optional: close the output file (can also be implicit when the script exits)
exec 3>&-
The other common idiom is to open in append mode using >>, but doing that once per line is considerably less efficient.
# Open ErrorLog.txt, truncating if it exist, write one line, and close it
echo "something" >ErrorLog.txt
# Reopen ErrorLog.txt, write an additional line to the end, and close it again
echo "something else" >>ErrorLog.txt
Putting this practice to work in your script (and making some other best-practice improvements) looks like the following:
#!/bin/bash
# not related to file output, but to making sure we detect errors
# only works correctly if run with bash, not sh!
set -o pipefail ## set exit status based on whole pipeline, not just last command
# picking 3, since FD numbers 0-2 are reserved for stdin/stdout/stderr
exec 3>ErrorLog.txt
if bro-cut service <conn.log | sort | uniq -c >ProtocolHierarchy.txt; then
echo "OK Protocol Hierarchy Created" >&3
else
echo "FAILED Creating Protocol Hierarchy" >&3
fi
if bro-cut id.orig_h <dns.log | sort | uniq -c >AllIPAddresses.txt; then
echo "OK Created all IP Addresses" >&3
else
echo "FAILED Creating all IP Addresses" >&3
fi

Shell script if condition not working in SVN pre-commit hook

need some help
I was trying to enhance the pre-commit hook to see if I can ignore parsing the commit message if there is a certain key ("!ignore") in the commit message
The if conditions before this one , like to check if there are empty commit messages works. But this if condition somehow is not working.
Ok when I do a commit with message "SMARTCOMMITTEST" which does not contain my check key "!ignore", the commit succeeds which means the If condition below never executed or did not execute as expected. So trying to understand what is wrong wit it.
SMARTCOMMIT=1
$SVNLOOK log -t "$TXN" "$REPOS" | grep "!ignore" | wc -c || SMARTCOMMIT=0
if [ $SMARTCOMMIT = 0];
then
echo "Please use !ignore if you dont want to use smart commits in your commit message." 1>&2
exit 1
fi
Thanks a lot to Etan for some tips...
I changed the condition like the other if condition in the comments and then it worked
SMARTCOMMIT=$($SVNLOOK log -t "$TXN" "$REPOS" | grep "!ignore" | wc -c)
if [ "$SMARTCOMMIT" = "0" ]; then
echo "Please use !ignore if you dont want to use smart commits in your commit message." 1>&2
exit 1
fi
This one worked fine..
#David W .. I now have a situation to check multiple conditions in the same if
SMARTCOMMIT=$($SVNLOOK log -t "$TXN" "$REPOS" | grep '!ignore' | wc -c)
COMMITMESSAGENOREVIEW=$($SVNLOOK log -t "$TXN" "$REPOS" | grep '#comment' | wc -c)
COMMITMESSAGEWITHREVIEW=$($SVNLOOK log -t "$TXN" "$REPOS" | grep '+review' | wc -c)
if [ "$SMARTCOMMIT" = "0" -a "$COMMITMESSAGENOREVIEW" = "0" -a "COMMITMESSAGEWITHREVIEW" = "0" ]; then
echo "Please use #comment or +review to enable smart commits or !ignore to not use smart commits." 1>&2
exit 1
fi
I tried as given in the link here but still I dont see the if condition getting executed at all. Can you help me with this now?
The if statement can look at the exit output of a command, so you don't need to set an environment variable depending upon the output:
shopt extglob > /dev/null && extglob=1
if ! $SVNLOOK log -t "$TXN" "$REPOS" | grep -q '!ignore'
then
echo 'Please use "!ignore" if you dont want to use smart commits in your commit message.' 1>&2
exit 1
fi
This runs $SVNLOOK log -t "$TXN" "$REPOS" | grep -q '!ignore'
The -q is quiet mode. grep either exits zero if the string exists or non-zero if it doesn't exist. By putting this in the if !, the then clause executes only if !ignore was found.
You have to make sure that !ignore is surrounded by single quotes, or you put a \ in front of the !. Bash has a csh type history mechanism in there, and there's no way to turn it off. Anytime the shell sees !, it assumes it has to do with the process ID number.

Pseudo-terminal will not be allocated because stdin is not a terminal ssh bash

okay heres part of my code when I ssh to my servers from my server.txt list.
while read server <&3; do #read server names into the while loop
serverName=$(uname -n)
if [[ ! $server =~ [^[:space:]] ]] ; then #empty line exception
continue
fi
echo server on list = "$server"
echo server signed on = "$serverName"
if [ $serverName == $server ] ; then #makes sure a server doesnt try to ssh to itself
continue
fi
echo "Connecting to - $server"
ssh "$server" #SSH login
echo Connected to "$serverName"
exec < filelist.txt
while read updatedfile oldfile; do
# echo updatedfile = $updatedfile #use for troubleshooting
# echo oldfile = $oldfile #use for troubleshooting
if [[ ! $updatedfile =~ [^[:space:]] ]] ; then #empty line exception
continue # empty line exception
fi
if [[ ! $oldfile =~ [^[:space:]] ]] ; then #empty line exception
continue # empty line exception
fi
echo Comparing $updatedfile with $oldfile
if diff "$updatedfile" "$oldfile" >/dev/null ; then
echo The files compared are the same. No changes were made.
else
echo The files compared are different.
cp -f -v $oldfile /infanass/dev/admin/backup/`uname -n`_${oldfile##*/}_$(date +%F-%T)
cp -f -v $updatedfile $oldfile
fi
done
done 3</infanass/dev/admin/servers.txt
I keep on getting this error and the ssh doesn't actually connect and perform the code on the server its suppose to be ssh'd on.
Pseudo-terminal will not be allocated because stdin is not a terminal
I feel like everything the guy above just said is so wrong.
Expect?
It's simple:
ssh -i ~/.ssh/bobskey bob#10.10.10.10 << EOF
echo I am creating a file called Apples in the /tmp folder
touch /tmp/apples
exit
EOF
Everything in between the 2 "EOF"s will be run in the remote server.
The tags need to be the same. If you decide to replace "EOF" with "WayneGretzky", you must change the 2nd EOF also.
You seem to assume that when you run ssh to connect to a server, the rest of the commands in the file are passed to the remote shell running in ssh. They are not; instead they will be processed by the local shell once ssh terminates and returns control to it.
To run remote commands through ssh there are a couple of things you can do:
Write the commands you want to execute to a file. Copy the file to the remote server using scp, and execute it with ssh user#remote command
Learn a bit of TCL and use expect
Write the commands in a heredoc, but be careful with variable substitution: substitution happens in the client, not on the server. For example this will output your local home directory, not the remote:
ssh remote <<EOF
echo $HOME
EOF
To make it print the remote home directory you have to use echo \$HOME.
Also, remember that data files such as filelist.txt have to be explicitly copied if you want to read them on the remote side.

Catching errors in Bash with glassfish commands [return code in pipes]

I am writing a bash script to manage deployments to a GF server for several environments. What I would like to know is how can I get the result of a GF command and then determine whether to continue or exit.
For example
Say I want to redeploy, I have this script
$GF_ASADMIN --port $GF_PORT redeploy --name $EAR_FILE_NAME --keepstate=true $EAR_FILE | tee -a $LOG
The variables are already defined. So GF will start to redeploy and either suceed or fail. I want to check if it does and act accordingly. I have this right after it.
RC=$?
if [[ $RC -eq 0 ]];
then echoInfo "Application Successfully redeployed!" | tee -a $LOG;
else
echoError "Failed to redeploy application!"
exit 1
fi;
However, it doesnt really seem to work .
The problem is the pipe
$GF_ASADMIN ... | tee -a $LOG
$? reflects the return code of tee.
Your are looking for PIPESTATUS. See man bash:
PIPESTATUS
An array variable (see Arrays below) containing a list of exit
status values from the processes in the most-recently-executed
foreground pipeline (which may contain only a single command).
See also this example to clarify the PIPESTATUS
false | true
echo ${PIPESTATUS[#]}
Output is: 1 0
The corrected code is:
RC=${PIPESTATUS[0]}
Or try using a code block redirect, for example:
{
if "$GF_ASADMIN" --port $GF_PORT redeploy --name "$EAR_FILE_NAME" --keepstate=true "$EAR_FILE"
then
echo Info "Application Successfully redeployed!"
else
echo Error "Failed to redeploy application!" >&2
exit 1
fi
} | tee -a "$LOG"

Resources