Bash Script with Multiple if statments - bash

So I am trying to get email notifications setup on about 100 servers and I am using an if script that works perfectly, however I have a tool that ssh's into each machine ever 5 min to gather statistics. I am trying to adapt the script to ignore any ssh attempts from 1 IP. I have racked my brain and I think I have looked through every possible question on the subject. Any help would be amazing thank guys!!!
Currently the script sends an email no matter who ssh's in.
#!/bin/sh
# Change these two lines:
sender="fromtest#test.com"
recepient="test#test.com"
if [ "$PAM_RUSER" != "192.168.1.10" ]; then
goto done
next
if [ "$PAM_TYPE" != "close_session" ]; then
host="`hostname`"
subject="SSH Login: $PAM_USER from $PAM_RHOST on $host"
# Message to send, e.g. the current environment variables.
message="`env`"
echo "$message" | mail "$sender" -s "$subject" "$recepient"
fi
fi

#!/bin/sh
# Change these two lines:
sender="fromtest#test.com"
recepient="test#test.com"
if [ "$PAM_RHOST" != "192.168.1.10" -a "$PAM_TYPE" != "close_session" ]; then
host="`hostname`"
subject="SSH Login: $PAM_USER from $PAM_RHOST on $host"
# Message to send, e.g. the current environment variables.
message="`env`"
echo "$message" | mail "$sender" -s "$subject" "$recepient"
fi
This solution uses a different conditional to skip the body of the if if the PAM_RHOST variable is equal to 192.168.1.10. We use -a (and) to specify that both conditions must be met.

Related

export environment varible from bash script with argument

I am trying to export environment variable using a bash script which takes one argument. I tried to run the script using source command, but it does not work.
source ./script.sh dev
My example script below
#!/bin/bash
# Check 1 argument is passed with the script
if [ $# -ne 1 ]
then
echo "Usage : $0 AWS account: e.g. $0 dev"
exit 0
fi
# convert the input to uppercase
aws_env=$( tr '[:lower:]' '[:upper:]' <<<"$1" )
if ! [[ "$aws_env" =~ ^(DEV|UAT|TRN|PROD)$ ]]; then
# check that correct account is provided
echo "Enter correct AWS account: dev or uat or trn or prod"
exit 0
else
# export environment variables
file="/home/xyz/.aws/key_${aws_env}"
IFS=$'\n' read -d '' -r -a lines < $file
export AWS_ACCESS_KEY_ID=${lines[0]}
export AWS_SECRET_ACCESS_KEY=${lines[1]}
export AWS_DEFAULT_REGION=ap-southeast-2
echo "AWS access keys and secret has been exported as environment variables for $aws_env account"
fi
Content of file /home/xyz/.aws/key_DEV. Its a sample only, not real keys.
$ cat key_DEV
123
xyz
When I say it does not work, nothing happens in the terminal, it closes the terminal when I run the script.
Further update:
When I run the script as is from the terminal without source (./script.sh dev) it seems to be working fine, with the debug (set -x), I can see all the outputs are correct.
However, the issue is when I run with source (source ./script.sh dev), then it fails (closes the terminal, now I know why, because of exit 0), and from the output captured from the debug command I can see that its not capturing $1 argument correctly. The error message "Enter correct AWS account: dev or uat or trn or prod". And, the value of $aws_env variable is blank.
I don't know why the two behaviors are different and how to fix it.
Final update:
The script seems to be fine. The issue was local to my computer. tr was defined as an alias in .bashrc file which was causing the problem. I just used typeset -u aws_env="$1" instead of aws_env=$( tr '[:lower:]' '[:upper:]' <<<"$1" ). Thank you all for helping me to get this one resolved, specifically #markp-fuso.
Try using mapfile instead of read like so...
#!/usr/bin/env bash
# Check 1 argument is passed with the script
if [ $# -ne 1 ]
then
echo "Usage : $0 AWS account: e.g. $0 dev"
exit 0
fi
# convert the input to uppercase
aws_env=$( tr '[:lower:]' '[:upper:]' <<<"$1" )
if ! [[ "$aws_env" =~ ^(DEV|UAT|TRN|PROD)$ ]]; then
# check that correct account is provided
echo "Enter correct AWS account: dev or uat or trn or prod"
exit 0
else
# export environment variables
file="/home/xyz/.aws/key_${aws_env}"
# IFS=$'\n' read -d '' -r -a lines < $file
mapfile -t lines < "$file"
export AWS_ACCESS_KEY_ID=${lines[0]}
export AWS_SECRET_ACCESS_KEY=${lines[1]}
export AWS_DEFAULT_REGION=ap-southeast-2
echo "AWS access keys and secret has been exported as environment variables for $aws_env account"
fi
Make sure you also put quotation marks around "$file"
Another little tip, Bash supports making variables uppercase directly, like so:
var="upper"
echo "${var^^}"

bash programming - best practice setting up variables within a loop or not

I have the following logic in my bash/shell script. Where essentially, I'm trying to pass one argument manually and then passing in other values from a hidden file, like so:
if [[ $# != 1 ]]; then
echo "./tstscript.sh <IDNUM>" 2>&1
exit 1
fi
MYKEY=/dev/scripts/.mykey
if [ -f "$MYKEY" ]
then
IFS=';'
declare -a arr=($(< $MYKEY))
# DECLARE VARIABLES
HOSTNM=localhost
PORT=5432
PSQL_HOME=/bin
IDNUM=$1
DBU1=${arr[0]}
export HOSTNM PORT PSQL_HOME IDNUM DBU1 DBU2
$PSQL_HOME/psql -h $HOSTNM -p $PORT -U $DBU1 -v v1=$IDNUM -f t1.sql postgres
else
echo "Mykey not found"
fi
rt_code=?
exit 1
Am I declaring my variables in the right place? Should it be declaring within my if statement?
Most of your variables are redundant. psql already has a few well-known environment variables it will use if you don't specify various parameters on the command line. The others are just hard-coded, so it's not really important to define them. It really doesn't matter much where you define them, as long as you define them before they are used, since this isn't a very large script. It's a good sign that you've outgrown shell script and are ready for a more robust programming language when you start worrying about the design of the shell script.
if [[ $# != 1 ]]; then
echo "./tstscript.sh <IDNUM>" 2>&1
exit 1
fi
MYKEY=/dev/scripts/.mykey
if ! [ -f "$MYKEY" ]; then
echo "Mykey not found"
exit 1
fi
# You only use the first word/line of the file,
# so this should be sufficient.
IFS=";" read -a arr < "$MYKEY"
export PGHOST=localhost
export PGPORT=5432
export PGUSER=${arr[0]}
: ${PSQL_HOME:=/bin}
"$PSQL_HOME"/psql -v v1="$1" -f t1.sql postgres
When you fill /dev/scripts/.mykey with lines in the form key=value, you can source that file.
$ cat /dev/scripts/.mykey
DBU1=noober
FIELD2="String with space"
echo "Keep it clean, do not use commands like this echo in the file"
In your script you can activate the settings by sourcing the file
if [ -f "${MYKEY}" ]; then
. "${MYKEY}"
# Continue without an array, DBU1 and FIELD2 are set.

shell scripting, how to run different code based on selection?

I have a shell script as below...
#!/bin/ksh
set_logging() {
if [ -f "$LOG_FILE" ]
then
mv $LOG_FILE $LOG_FILE.$SYNCDATE
else
touch $LOG_FILE
fi
# set logging for stdout and stderr (run this if user selects start)
exec >> $LOG_FILE
exec 2>&1
# run this if user selects dry
#exec something else
#exec something else
}
set_logging
# menu
if [[ ! -n $1 ]] ; then
clear
echo ""
echo "What are you trying to do?"
echo "start"
echo "dry"
echo "help"
echo ""
exit 99
fi
case "$1" in
start) run_tar;;
dry) nothing_here_yet;;
help) print_help;;
*) clear
echo "Your syntax is incorrect!"; exit 99;;
esac
This is a snipped of the actual script, running on AIX 7.1 UNIX OS.
What I am trying to do is based on user selection on the menu, change what parts get executed within the set_logging() block (you'll notice I commented the code I want to run if user selects different menu option just to help this example).
Again, this is an example to keep it simple so I understand and can use it in different parts of my shell script.
Anyone able to help?
I'm not totally clear of some details. If you put the following code at the top where the comments are, then it won't really work because $1 might not be set. It needs to go after the test if $1 is empty. For what you describe, you don't need something as complex as a case statement. You can do it with an if statement like:
if [[ "$1" = "dry" ]] ; then
exec something
exec somethingelse
fi
You want the $1 inside quotes. Otherwise, if it is not set, $1 disappears entirely and the statement becomes invalid. Likewise with the if test that you have, you should put the $1 inside double quotes.
You can use = or == depending upon lots of factors. Generally = and == are equivalent with a few exceptions (e.g. very old bourne shell does not have ==, etc.)
Last [[ ! -n $1 ]] is probably better written [[ -z "$1" ]]

Assigning variables causes SFTP to fail

I'm trying to write a shell script that grabs a set of parameters from a text file and then performs SFTP based on those parameters. Basically, I'm taking a daily webstats log and moving it to a central location.
The issue I'm having is that the SFTP fails based on the way I am assigning variables. I have debugged and found that the while loop works correctly by echoing out the loop of variables. The error I get is that the connection is closed.
#!/bin/sh
source /home/ntadmin/webstats/bin/webstats.profile
source /home/ntadmin/webstats/bin/webstats.blogs.profile
DATE=`date +%m%d%Y`
SOURCE_FILE="`echo $WS_BC_SOURCE_FILE | sed -e 's/mmddyyyy/'$DATE'/'`"
IFS=","
while read WS_BLOG_NAME WS_BLOG_SOURCE_VAR WS_BLOG_DEST_VAR WS_BC_SERVER1;
do
#Step 1 SFTP
cd $PERL_DIR
if $PERL_DIR/sftp.pl $WS_BC_SERVER1 $WS_BC_ID $WS_BC_PW $WS_BLOG_SOURCE_VAR/$SOURCE_FILE $WS_BLOG_DEST_VAR/$SOURCE_FILE
then
echo 'SFTP complete'
else
echo 'SFTP failed!'
exit 1
fi
#Step 2 - Check that ftp was successful (that the files exist)
if [ -e $WS_BLOG_DEST_VAR/$SOURCE_FILE ]
then
echo "FTP of $WS_BLOG_SOURCE_VAR/$SOURCE_FILE from $WS_BC_SERVER1 was successful"
else
echo "FTP of $WS_BLOG_SOURCE_VAR/$SOURCE_FILE from $WS_BC_SERVER1 was not successful!"
exit 1
fi
done < blogs_array.txt
exit 0
There is not enough information to determine what was wrong, but here is a debugging method.
Try replace the actual sftp command in perl script with a debug script like this, you should be able to locate the problem quickly.
#!/usr/bin/perl
print "arguments passed to $0\n";
$i=0;
while (defined $ARGV[$i]) {
print "arg ".($i+1)." is <$ARGV[$i++]>\n"
}

Bash: Only allow Pipe (|) or Redirect(<) to pass data, and show usage otherwise

I have a script which takes in several arguments.
Now, I have modified the script to except multiple file names and operate on them.
I also want this script to execute when I am receiving input via a pipe (|) or a redirected input (<).
But, I do not want the script to wait for input on terminal when none of the above three inputs are provided, and rather show usage instructions.
I am using the following function:
# PIPED CONTENT
if [ "$#" == "0" ]; then
READINPUT="1"
if [ "x$TEXTINPUT" == x"" ]; then
READINPUT=1
TMPFL=`tempfile -m 777`
while read data; do
echo "${data}" >> $TMPFL
done
TEXTINPUT="`cat $TMPFL`"
rm $TMPFL
fi
# if [ "x$TEXTINPUT" == x"" ]; then
# if [ "$#" == "0" ]; then usage; fi
# fi
fi
Any help is appreciated.
Regards
Nikhil Gupta
if test -t 0; then
echo Ignoring terminal input.
else
process -
fi
The -t test takes a file descriptor as parameter (0 is stdin) and returns true if it is a terminal.
Please be aware that there are two different "test" commands: the built in bash command, and the "test" program which is often installed as /usr/bin/test, part of the coreutils package. The two provide the same functions.
[[ -t 0 ]]
is equivalent to
/usr/bin/test -t 0
You may run either of the above on a "bash" command line, with the same results.

Resources