Bash Script Help "if (user input) = then (var) =" - bash

I a writing a script to cherry pick all open changes from Gerrit. I found one that works sort of, though I need to be able to change inputs so that I do not have a script for each repo hardcoded with that specific repo's information.
#! /bin/sh
REMOTE="${1-review}"
ssh -p 29418 user#gerrit.remote.com gerrit query --format=text --patch-sets status:open branch:XXX project:XXX | grep revision: | awk '{print $2;}' | while read ID
do
git fetch "${REMOTE}" && git cherry-pick "${ID}"
done
Now I have been able to pick open changes successfully but I am trying to make it so I can pass input to change username, branch, project and remote. With the current method I need to enter my username, project, branch, and remote manually into the script. Then it is only good for that specific repo.
I have been having trouble with if/then statements. I know as it looks now none of the things I am asking for are coded, I wanted to provide someone with a working model though.
I did change username and the particular details, easy enough for someone to use this script themselves to cherry-pick by inserting the requisite information.
If I do something like this:
PROJECT="$1"
if [ "$1" = "XX" ]; then
"$PROJECT="project:name of project"
Then bash returns XX command not found. I am not trying to make it a command I want it to be input to be inserted into the ssh command later on. Also I am trying to not only use if but also else if so that PROJECT can be whatever is input.
I think I am almost there though completely stumped at this point.

Assume $1 is equal to "XX". Your code:
PROJECT="$1"
will assign PROJECT=XX. Next,
if [ "$1" = "XX" ]; then
is true, "then" clause will be executed. This clause is:
"$PROJECT="project:name of project"
that tries to execute command "XX=...", causing "command not found"
Suggestion, remove $ on this line, as in:
PROJECT="project:name of project"

Related

command git submodule foreach 'git tag -l | echo "HELLO"' always echo HELLO

I'm on a wsl Ubuntu 20.04 and cannot comprehend why my command does not seem to take into account my first parameter as if it has trouble interpreting the quotes. Any idea on what is going on here?
Thanks in advance for your help
As already mentioned in the comments, | is a pipe, so any output of git tag -l is piped to echo and because echo does not really read the input, just ignores it, all you get is "HELLO".
The OR operator, ||, is probably what you want, although it won't work just like that with git tag -l, because that command returns success even if there are no tags. But in the comments you mention that what you actually want is git tag -d TAG. That should work fine, because it returns failure when TAG does not exist.
You also worry that using OR operator would prematurely stop processing your modules. The opposite is actually true. From the documentation:
A non-zero return from the command in any submodule causes the processing to terminate. This can be overridden by adding || : to the end of the command.
So without || the processing will stop on the first submodule, which doesn't have TAG.
In case you want it to work with git tag -l too, you have to somehow make it return failure if there are no tags. One way, maybe not the best, is pipe its output to grep ".*". Some example:
]$ git submodule foreach 'git tag -l "v5.0*beta1" | grep ".*" || echo "NOT FOUND"'
Entering 'qtactiveqt'
v5.0.0-beta1
Entering 'qtbase'
NOT FOUND
Entering 'qtqa'
v5.0.0-beta1
Entering 'qtrepotools'
v5.0.0-beta1

Git pre-push to prevent merge

i made this bash script for my git hooks in order to avoid merging by mistake.
At work we use git-extension and it prefills the branch name, if you forget to prefix the branch name by refs/for or refs/drafts then your commits are merged on the distant repo bypassing the code review.
This can only happen to people with merge right. but sometimes someone with merge right will make that mistake.
#!/bin/sh
if [[ `grep 'refs/for'` ]]; then
echo "push to refs/for/ authorized"
elif [[ `grep 'refs/drafts/'` ]]; then
echo "push to refs/drafts/ authorized"
else
echo "PUSH DENIED, MERGE DETECTED, please merge using gerrit 'submit' button only"
exit 1
fi
if I push to refs/for/v1.1.x it get push to refs/for/ authorized
however if I push to refs/drafts/v1.1.x I get PUSH DENIED, MERGE DETECTED, please merge using gerrit 'submit' button only
How is this possible, the condition syntax is exactly the same.
Thanks.
As Anthony Sottile commented, your first grep command reads all the input, checking for refs/for. Your second grep reads the remaining input; since your first one read all of the input, none remains. The second one therefore never finds anything.
You can deal with this in many different ways. One is to copy stdin to a temporary file that you can read repeatedly. Another is to structure your hook so that you read the input only once, checking each line for each condition. This second method is obviously more efficient, though this "obviousness" is a bit of an illusion, depending on details I'm not going to get into here.
Anyway, the way I would write this is:
#! /bin/sh
summary_status=0 # assume all OK initially
while read lref lhash rref rhash; do
case $rref in
refs/for/*|refs/draft/*) echo "push to $rref ok";;
*) echo "push to $rref not ok"; summary_status=1;;
esac
done
exit $summary_status
This variant does not require bash features (hence the /bin/sh rather than /bin/bash in the #! line); if you change it to one that does, be sure to change the #! line. It reads the input exactly once. It also verifies that you did not run, e.g.:
git push remote master:refs/for/master develop
which your existing script would allow (since one is OK and one is not).

Respond to a prompt in a shell script

I am learning to write bash scripts when I ran across this doubt. Have a look at the script below. It is not the actual script but is perfect to put my point.
#!/bin/bash
firstName = "Tony"
lastName = "Stark"
init
#The command prompts here:
# > Hello!
# > bla blah
# > What is your name?
echo firstName
# > bla blah
# > Now you may enter your last name
echo lastName
Problem: So what I want to achieve is to echo only when the command prompts for What is your name?. I want to wait until prompt asks this specific question and then echo the stuff automatically. I am trying to automate this data using the script.
I tried the read command but it didn't work as thought. Is there a good way to do it? Anybody willing to shed some light is greatly appreciated. Thanks in advance!
Edit: Consider this for an instance. Please don't look at the security risks for this example. Lets automate git push.
#!/bin/bash
username: "un"
password: "pd"
git add -A
git commit -m "Update"
# returns a commit message in a second or so. It can throw an error. So `read` can not know how many lines to read. Execute the next command after reading whatso ever is the result(for now)
read message #ignore whatever the message is
git push origin master
# Now it asks for username. What I want is to echo the username on when it outputs: `Username for 'https://github.com':`
echo username
# Asks `Password for un:`
echo password
I know it has many security and functional loopholes. But I want to know is the particular way to automate echoing after a specific question is asked.

Why does my menu with select fail the first time?

I tried to answer another SO question with a simple menu using the builtin select statement. The code displays names from /etc/passwd, and let you select a name by giving a number:
PS3="Enter a number: "
select name in $(cut -d: -f1 /etc/passwd) ; do
if [ -n "${name}" ]; then
break
fi
echo "Sorry, please enter a number as shown."
done
echo "Entry from passwd is: ${name}"
The works fine except for the very first time. When you give a correct answer the first time it will ask you to try again.
I tried to get a more detailed explanation of the first time, but I couldn't get a reproducable cook-book. When you copy-paste this code on your server, and give a correct answer you will probably have the same problem. When you repeat the command (from history or a new paste), the code shows now problem. I tried to get the problem again by logging out and logging in (sometimes it works) or rebooting.
I tried different ways to reproduce the problem in other situations (using different variable names, unsetting variables, using a slow list of values with select name in $(echo One; sleep 1; echo Two; sleep 2; echo Three; sleep 1); and opening a new shell.
I searched for other examples with select, but I can't find clues in other posts like https://stackoverflow.com/a/16750755/3220113 and https://askubuntu.com/a/1716.
I tried to fix my code with a sync and that seems to be a work-around:
PS3="Enter a number: "
select name in $(cut -d: -f1 /etc/passwd) ; do
# is sync needed here?
sync
if [ -n "${name}" ]; then
break
fi
echo "Sorry, please enter a number as shown."
done
echo "Entry from passwd is: ${name}"
I couldn't reproduce the error when I include the sync command. Is sync really a working patch and why do I need this here?
I do not need other ways to write a menu. I already found the graphical dialog Dialog from bash script and was looking for a simple replacement of my own over-complicated https://unix.stackexchange.com/a/115371/57293.
This problem only occurs when you type the commands interactively, not in a script. The reason is that the line you type after the select line is being used as the response to the prompt. Since if isn't in the menu, it reports an error. Then it doesn't execute the if command, because it was read as the response to the prompt.
It's not a problem in a script because the commands in the script are not used as standard input.

bash overriding a single line in a text file with another while using variables

Overview: I am trying to make a script that will take a list of machines and manually update their /etc/shadow files with a new root passwd. I know this isn't the best method but my boss wants this process automated. we are using a application called puppet for 90% of the update but some machines failed the update or can't have puppet installed, hence this dodgy fix.
(sorry for any stupid errors its only my 3rd week using any unix product, I have been a windows admin my whole life)
Issue:
I need to ssh into the PC's update the /etc/shadow file but only change the root user (not all systems have the same users and I don't want to remove any of those users in the process) I have gotten as far as being able to extract the current user in line 1 through ssh, then check if that user is indeed the root user but I am stuck on then updating the /etc/shadow file on the new machine as my boss has asked that the following standards happen.
I can't have any real user interaction in the script, so no manually typing the new passwd.
I am not allowed to have the new passwd displayed anywhere in clear text (inside the script or in another file)
Ok hopefully that's enough info onto the code.
root=user
unknown='unknown.txt'
filelines=`cat $unknown`
prod='new-shadow'
ohf='option-one-holding-file'
pel=prod-errorlog
for line in $filelines ; do
echo "Attempting to fix $line please wait"
ssh -oBatchMode=yes -l $user $line "awk '{if (NR==1) print \$0}' /etc/shadow" >> $ohf
if grep -q "root:" $ohf ; then
echo "root user located updating to produtcion password"
# ** This is the line that doesn't work **
ssh -oBatchMode=yes -l $user $line "sed -i '1s/.*/$prod/' /etc/shadow"
else
echo "unable to find root user this will require a manual fix this server will be listed in
the prod-errorlog file"
echo "$line" >> $pel
fi
done
The line in bold the sed line doesn't work I know why it doesn't work but I have no idea how to fix it at all, thank you to anyone who takes the time to look at this, I know the codes a bit of a mess, please forgive me.
To replace only the first line:
"echo '$prod' > /etc/shadow.new; tail -n +1 /etc/shadow >> /etc/shadow.new; mv -f /etc/shadow.new /etc/shadow"
Sorry for my previous wrong argument wrong: The '$prod' part in your script is correct, and is expanded OK. Yet $prod contains many reserved characters for regular expressions. Now this new version just create a new file (replacing the first line) and then move/overwrite on to the target one.

Resources