Bash Script works locally but not from server - bash

I have a script which runs fine when executed locally on a mac.
# Ask to make system changes
read -p "Would You Like to make system changes? (Finder, etc...) ? (y/n)?" CONT
if [ "$CONT" == "y" ]; then
# Keep-alive: update existing `sudo` time stamp until `mac.sh` has finished
echo "Keep this mac alive while ding this task..."
while true; do sudo -n true; sleep 60; kill -0 "$$" || exit; done 2>/dev/null &
# Show Date on menubar
echo "Showing Date on menubar..."
defaults write com.apple.menuextra.clock.plist DateFormat "EEE dd MMM h:mm:ss a"
killall "SystemUIServer";
else
echo "Done makng system changes"
fi
But when I try remotely like this:
curl -s https://192.168.63.23/mac.sh --insecure | sh
I get this error:
sh: line 93: syntax error near unexpected token `else'
sh: line 93: `else'

You aren't executing anything remotely; you are just copying the script from a remote server to execute locally. One problem is that your script uses bash extensions like read -p, but you are executing it with sh (which, even if it is a link to bash, executes in POSIX mode). Use bash explicitly:
curl -s --insecure https:/192.168.63.23/mac.sh | bash
As for the syntax error, run your code through shellcheck.net. You haven't shown enough of the actual code to locate the problem.

Related

Clear last bash command from history from executing bash script

I have a bash script, which uses expect package to ssh into a remote server.
My script looks like this:
#!/bin/bash
while getopts "p:" option; do
case "${option}" in
p) PASSWORD=${OPTARG};;
esac
done
/usr/bin/expect -c "
spawn ssh my.login.server.com
expect {
\"Password*\" {
send \"$PASSWORD\r\"
}
}
interact
"
I run it like ./login.sh -p <my-confidential-password>
Now once you run it and log in successfully and exit from the remote server, I can hit up-arrow-key from the keyboard and can still see my command with password in the terminal. Or I simply run history it shows up. Once I exit the terminal, then it also appears in bash_history.
I need something within my script that could clear it from history and leave no trace of the command I ran (or password) anywhere.
I have tried:
Clearing it using history -c && history -r, this doesn't work as the script creates its own session.
Also, echo $HISTCMD returns 1 within script, hence I cannot clear using history -d <tag>.
P.S. I am using macOS
You could disable command history for a command:
set +o history
echo "$PASSWORD"
set -o history
Or, if your HISTCONTROL Bash variable includes ignorespace, you can indent the command with a space and it won't be added to the history:
$ HISTCONTROL=ignorespace
$ echo "Hi"
Hi
$ echo "Invisible" # Extra leading space!
Invisible
$ history | tail -n2
7 echo "Hi"
8 history | tail -n2
Notice that this isn't secure, either: the password would still be visible in any place showing running processes (such as top and friends). Consider reading it from a file with 400 permissions, or use something like pass.
You could also wrap the call into a helper function that prompts for the password, so the call containing the password wouldn't make it into command history:
runwithpw() {
IFS= read -rp 'Password: ' pass
./login.sh -p "$pass"
}

Automatize the cert creation OpenVPN

I do not know why I am getting an error when I run my script with SSH, but when I run the bash from my CA server everything works fine.
I installed my VPN server based on this article https://www.digitalocean.com/community/tutorials/how-to-set-up-an-openvpn-server-on-ubuntu-18-04
I wrote a bash for the VPN creation but when I try to run it I need to SSH to the other server at some point. If I start the script with SSH in it I got an error message:
>./easyrsa: 341: set: Illegal option -o echo
My bash contain this and run from my VPN server:
sshpass -p $PASSWORD ssh username#"CA server IP" "/home/username/makevpn.sh $NAME $PASSWORD"
And makevpn.sh contain this:
>./easyrsa sign-req client $NAME
After this run it seems okay but give that error above.
I tried to read after this error and found nothing. :( Hope someone can help because I am hopeless after 4 days of troubleshooting.
Code of VPN script
#!/bin/sh
clear
read -p "Please enter the name of the new certificate : " NAME
read -p "Please enter the Password : " PASSWORD
cd /home/username/EasyRSA-3.0.7/
./easyrsa gen-req $NAME nopass
echo "gen-req done"
cp /home/username/EasyRSA-3.0.7/pki/private/$NAME.key /home/username/client-configs/keys/
echo "cp done"
sshpass -p $PASSWORD scp /home/username/EasyRSA-3.0.7/pki/reqs/$NAME.req username#192.168.1.105:/tmp
echo "scp done"
sshpass -p $PASSWORD ssh username#192.168.1.105 "/home/username/makevpn.sh $NAME $PASSWORD"
echo "ssh done"
cp /tmp/$NAME.crt /home/username/client-configs/keys/
echo "last CP done"
sudo /home/username/client-configs/make_config.sh $NAME
echo "All Done"
Code on CA server
#!/bin/sh
NAME=$1
PASSWORD=$2
cd /home/username/EasyRSA-3.0.7/
echo "CD Done"
./easyrsa import-req /tmp/$NAME.req $NAME
echo "Import-req done"
./easyrsa sign-req client $NAME
echo "Sign-req done"
sshpass -p $PASSWORD scp /home/username/EasyRSA-3.0.7/pki/issued/$NAME.crt username#192.168.1.103:/tmp
echo "Scp done"
I was just browsing the code of that easyrsa script here. This one is likely different from yours given the line for the error is 341. On the Github page, it is line 352 and it is part of a function called cleanup. It appears that this function is only attached as a trap (line 2744). Traps are used to catch signals like sigint (interrupt) which is normally sent on the terminal with ctrl+c (and may display a character like ^C). The reason the error only displays in your script is it likely causes a signal to be emitted that you would not normally receive if you ran it manually over ssh.
The error itself is really not an issue.
Code from Github:
Line 352:
(stty echo 2>/dev/null) || { (set -o echo 2>/dev/null) && set -o echo; }
Line 2744:
trap "cleanup" EXIT
It appears that line is just trying to turn terminal output of your typed characters back on (via stty echo). Sometimes programs will disable terminal output somewhere, and then re-enable it when the program finishes. However, if you were to kill the program mid way through (e.g. with ctrl+c), your program would terminate with the terminal output still disabled. This would make the terminal appear to be frozen. It would still work, but would not display the characters you type with your keyboard. The point of the trap is to ensure that terminal output is re-enabled no matter how the program exits.
More info...
At line 567 there is a function that disables echo. Looks like the point is to not show a password to the screen. If you were to kill the program during password reading, echo would remain disabled on the terminal. Likely the reason for the error has more to do with the way you are running the script. For whatever reason it causes stty echo to fail. Line 352 is assuming that the failure is due to stty echo not being a valid command. So on failure ( || ), it tries a different method (set -o echo) of enabling echo. If I try to run that on my terminal, I also get an error (bash 4.2):
-bash: set: echo: invalid option name

Command output redirection works only from console, not from script

I would like to capture command output to variable in bash, but display it as well to console.
exec 5>&1
STATUS=$(zypper info rar|tee >(cat - >&5))
echo $STATUS
It works in console expected way. When calling within following simple script, it works as well expected way.
#!/bin/bash
exec 5>&1
STATUS=$(zypper info rar|tee >(cat - >&5))
echo $STATUS
But when calling within following script, it produces error.
#!/bin/sh
#
# description: currency_trader_tools installation script
# Currency_Trader software.
#
# prerequisities:
# OpenSuse Leap 42.1 x86_64
# clean installation of Minimal Server Selection (Text mode)
# install:
# Midnight Commander - linux file manager
# x11vnc - X11 vnc server
# xvfb-run - X11 virtual frame buffer server
# java - latest JDK environment rpm
#
# commit_id = "0f46a17011ca82c57ddb7f81636984c7bebd5798";
# build_revision_full = "Build 0144 created 2016-05-11 18:04:00 based on commit 0f46a17011ca82c57ddb7f81636984c7bebd5798";
# build_revision_short = "0f46a17";
# build_revision = "0144";
RETVAL=0
ZIP_FILE_VERSIONED="Currency_Trader_Bash_Scripts_0_9_1- r-0144-0f46a17.zip"
ZIP_FILE="Currency_Trader_Bash_Scripts_0_9_1.zip"
# See how we were called.
if [[ ! `whoami` = "root" ]]; then
echo "You must have administrative privileges to run this script"
echo "Try 'sudo ./currency_trader_tools_install'"
exit 1
fi
exec 5>&1
STATUS=$(zypper info rar|tee >(cat - >&5))
echo
echo $STATUS
case "$1" in
all)
install_all
;;
*)
echo $"Usage: currency_trader_tools_install {all}"
exit 1
esac
exit $RETVAL
Error is:
./Currency_Trader_Bash_Scripts_0_9_1-Install-Script: command substitution: line 34: syntax error near unexpected token `('
./Currency_Trader_Bash_Scripts_0_9_1-Install-Script: command substitution: line 34: `zypper info rar|tee >(cat - >&5))'
Any recommendation, how to make the same using sh and not bash?
>(...) is not part of the POSIX standard, so you would need to use an explicit named pipe. However, managing this properly could get tricky. Just capture the output, and output to the console explicitly.
STATUS=$(zypper info rar)
echo "$STATUS"
(The script is already outputting the captured output to the terminal; there doesn't seem to be any need for tee in the first place.)

Running df -k command for my application server,and it is having mount issue,so need to trigger a mail

I an running df -k command for my application server, and it is having mount issue.
So I need to trigger a mail saying that the server is having mount issue.
My basic question, I will write a shell script which will run df -k command and identify if the command takes long time to complete the command, then I need to trigger a mail.
How can I do this ?
This question lists ways to detect stale NFS mounts: Is there a good way to detect a stale NFS mount
Select one solution and run it before the df -k.
Alternatively, you can redirect stderr to stdout and then grep for the error pattern:
df -k 2>&1 | grep ...error...
if [[ $? -ne 0 ]]; then
...send mail...
fi
It's not clear what exactly you're trying to archive; but timing how long a command takes is fairly easy, for example:
#!/bin/sh
start=$(date +%s)
out=$(sleep 6)
took=$(($(date +%s) - $start))
if [ $took -gt 5 ]; then
echo "$out" | mail -s "Command took too long" test#example.com
fi
Edit
This required the command to finish; if you want to have a timeout, I'd recommend using Python. It is possible with shell scripting, but IMHO this is much easier.
#!/usr/bin/env python
import subprocess, smtplib
from email.mime.text import MIMEText
proc = subprocess.Popen(['sleep', '100'])
try:
proc.wait(5) # 5 is the timeout in seconds
except subprocess.TimeoutExpired:
proc.kill()
# Send email
msg = MIMEText("Command took too long\r\n")
msg['Subject'] = 'Command took too long'
msg['From'] = 'test#example.com'
msg['To'] = 'test#example.com'
s = smtplib.SMTP('localhost')
s.sendmail('test#example.com', ['test#example.com'], msg.as_string())
s.quit()

How can I prevent bash from reporting an error when attempting to call a non-existing script?

I am writing a simple script in bash to check whether or not a bunch of dependencies are installed on the current system. My script attempts to run a sample script with the -h flag, greps the output for a keyword i would expected to be returned by the sample scripts, and therefore knows whether or not the sample script is installed on the system.
I then pass this through a conditional statement that basically says sample scripts = OK or sample scripts = FAIL. However, in the case in which the sample script isn't installed on the system, bash throws the warning -bash: sample_script: command not found. How can I prevent this from displaying? I tried using the 1>&2 error redirection, but the warning still appears on the screen (I want the OK/FAIL output text to be displayed on the user's screen upon running my script).
Thanks for any suggestions!
If you just want to suppress errors (stderr) and let the "OK" or "FAIL" you are echoing (stdout) pass through, you would do:
./yourscript.sh 2> /dev/null
Although the better approach would be to test whether sample_script is executable before trying to execute it. For instance:
if [ -x "$script" ]; then
*do whatever generates FAIL or OK*
fi
#devnull dixit
command -h 2>/dev/null
I use this function to be independent of which, whence, type -p and whatnot:
pathto () {
DIRLIST=$(echo "$PATH"|tr : ' ')
for e in "$#"; do
for d in $DIRLIST; do
test -f "$d/$e" -a -x "$d/$e" && echo "$d/$e"
done
done
}
pathto script will echo the full path if it can be found (and is executable). Returning 0 or 1 instead left as an exercise :-)
for bash:
if ! type -P sample_script &> /dev/null; then
echo Error: sample_script is not installed. Come back later. >&2
exit 1
fi
sample_script "$#"

Resources