Function throwing an error "Syntax error: "}" unexpected" in shell script - linux

#! bin/env sh
function idle_tm_ubu {
sudo apt remove npsrv
sudo rm -rf /etc/npsrv.conf
sudo rm -rf /var/log/npsrv.log
IDLE = /etc/npsrv.conf
if [ ! -f "$IDLE" ]; then
echo "Idle time out has been removed."
else
echo "Idle time out has not been removed"
fi
}
if [ "${AWSSTATUS}" = "active" ]
then
echo "Amazon ssm agent is $AWSSTATUS"
idle_tm_ubu
fi
When I execute this I get the error
Syntax error: "}" unexpected
How do I solve this?

You have a few simple errors you need to correct. To begin
IDLE = /etc/npsrv.conf
should be
IDLE=/etc/npsrv.conf
No spaces are allowed around = when used for assignment.
Always paste your script into ShellCheck to find errors and warnings. Then fix them.
Note the 'function' keyword is non-standard. Use 'foo()' instead of 'function foo'.
Also ensure the path to your interpreter
#! bin/env sh
is an ABSOLUTE path. bin/env is a RELATIVE path, did you mean /bin/env?

Related

Tomcat 9 not starting on linux - Catalina.sh can't use JAVA_OPTS

We have a new Tomcat 9 installed but we're having an issue when starting it.
It seems catalina.sh isn't able to work with the JAVA_OPTS, here what the log says :
/usr/local/tomcat-d-9/bin/catalina.sh line 507: -DWEBAPP-CONF-ROOT=/usr/local/webapps-conf/: No such file or directory
/usr/local/tomcat-d-9/bin/catalina.sh line 508: -Dcas.url=https://myurl.dev.com/cas/: No such file or directory
/usr/local/tomcat-d-9/bin/catalina.sh line 515: -Dapp.id=tomcat-d-9: command not found
The WEBAPP repo (line 507) actually exists so I'm confused, also why is it interpreting a url (line 508) as a dir/repo ?
These are only 3 examples of the errors in the log to illustrate the issue, but this is happening for every single JAVA_OPTS in my setenv.sh . It's either :
"no such file or directory" : but the file/directory actually exists
"no such file or directory" : but it's for a url
"command not found" : but it's not a command to run, just a parameter
I'm fairly new to this so I might be missing something obvious. Any idea what could be happening here ?
Here's my setenv.sh
#!/bin/bash
COMMON="/usr/local/etc/BashStartFunctions.bash"
[ ! -e "$COMMON" ] && echo "Missing $COMMON" && exit 1
source $COMMON
checkUsr
fetchAppEnv
echo "PRG=$1"
JAVA_OPTS="${JAVA_OPTS_EXTRA}
-Dspring.profiles.active=dev
-Djava.library.path=/usr/lib64:/usr/local/tomcat-apr-connector/lib:/lib64
-DWEBAPP-CONF-ROOT=${WEBAPP_CONF_ROOT}
-Dcas.url=${CAS_URL}
-Dserver.url=${SERVER_URL}
-Dcom.vmd.xmltcp.client.XmltcpClient.reuseClientSocket=false
-Dcom.aubesoft.jdbc.recovery.ChainedJdbcExecutionWithRecoveryHelper.overrideChainProcessorRecoveryFile=${overrideChainProcessorRecoveryFile}
-Dcom.aubesoft.jdbc.recovery.ChainedJdbcExecutionWithRecoveryHelper.overrideInChainRecoveryFile=${overrideInChainRecoveryFile}
-Dcom.aubesoft.jdbc.recovery.RecoveryPolicy.overrideDefaultRecoveryFile=${overrideDefaultRecoveryFile}
-Djavax.net.ssl.trustStore=${TRUSTSTORE}
-Dapp.id=${APP_ID}
-Dserver.xml.serverPort=${SERVER_PORT}
-Djava.awt.headless=true"
if [ "$1" = "start" ];then
JAVA_OPTS="${JAVA_OPTS}
-Denv=${APP_ENV}
-Dtomcat.hosts=${TOMCAT_HOSTS}
-Dstore.url=${store_url}
-Dlog.dir=${LOG_DIR}
-Dserver.xml.httpPort=${HTTP_PORT}
-Dserver.xml.ajp13Port=${AJP13_PORT}
-Dserver.xml.ajp13.maxThreads=${AJP13_MAX_THREADS}
-Dserver.xml.httpsPort=${HTTPS_PORT}
-Dserver.xml.https.maxThreads=${HTTPS_MAX_THREADS}
-Dserver.xml.https.sslCertFile=${HTTPS_CERT_FILE}
-Dserver.xml.https.sslCertKeyFile=${HTTPS_CERT_KEY_FILE}
-Dserver.xml.https.sslKeystoreFile=${HTTPS_KEYSTORE_FILE}
-Dserver.xml.https.sslKeystorePass=${HTTPS_KEYSTORE_PASS}
-Dserver.xml.https.sslKeyAlias=${HTTPS_KEYSTORE_KEY_ALIAS}
-Dserver.xml.jvmRoute=${HOSTNAME}.${AJP13_PORT}
-Dserver.xml.maxHeaderSize=${MAX_HEADER_SIZE}
-Dcom.sun.management.jmxremote
-Dcom.sun.management.jmxremote.port=${JMX_PORT}
-Dcom.sun.management.jmxremote.ssl=false
-Dcom.sun.management.jmxremote.authenticate=false
-Dscoperta.zone=${SCOPERTA_ZONE}
-Dscoperta.env=${APP_ENV}
-Dhttps.protocols=TLSv1
-Dsmartd.authentication.signing.secret.file=${SMARTD_AUTHENTICATION_SIGNING_SECRET_FILE}
-Dspring.profiles.active=${SMARTD_SPRING_PROFILES}
"
if [ ! -z ${CAS_SECURE} ]; then
# CAS args
JAVA_OPTS="${JAVA_OPTS} -Djava.security.auth.login.config=${JAAS_CONFIG}
-Djava.security.krb5.kdc=${KRB5_KDC}
-Djava.security.krb5.realm=${KRB5_REALM}
-Dcas.TGTTimeoutMS=${CAS_TGT_TIMEOUT_MS}
-Dcas.secure=${CAS_SECURE}"
fi
fi
CATALINA_OUT=/usr/local/tomcat-d-9/logs/catalina_${APP_ID}.out
echo "JAVA_OPTS=$JAVA_OPTS"
You're splitting up your settings into multiple lines:
-DWEBAPP-CONF-ROOT=/usr/local/webapps-conf/: No such file or directory
does not refer to /usr/local/webapps-conf/ not existing, but -DWEBAPP-CONF-ROOT=/usr/local/webapps-conf/ not existing (obviously)
You can escape the linebreaks using a \, e.g.
JAVA_OPTS="${JAVA_OPTS} \
-Denv=${APP_ENV} \
-Dtomcat.hosts=${TOMCAT_HOSTS} \
....
or
JAVA_OPTS="${JAVA_OPTS} -Denv=${APP_ENV}"
JAVA_OPTS="${JAVA_OPTS} -Dtomcat.hosts=${TOMCAT_HOSTS}"
....
or just write them all in a single line.
Also, consider to use CATALINA_OPTS, rather than JAVA_OPTS.

how to prevent an error from breaking a loop

if a string contains less than the number of characters you're trying to remove with this command:
(4 characters in this example)
variable1=${string::-4}
and this command is within a loop,the error causes the loop to break
is there anyway to prevent the loop from breaking, without first running a command to check if the string has more than 4 characters?
..like a "ignore error and continue anyway" command?
This is likely a side-effect of using set -e or set -o errexit to exit on error.
You cannot prevent this string indexation to throw an error if the index is invalid for the input string.
So you have to actually check the index will be valid within the string like:
#!/usr/bin/env bash
set -o errexit
for string in 'Hello abcd' '42' 'worldfour' '!here'; do
if [ ${#string} -ge 4 ]; then
variable1=${string::-4}
else
variable1=
fi
printf '%s' "$variable1"
done
echo

undefined variable error in csh script

I have one function in csh script and in this function I am using one variable which is sourced from one file. But while using script its throwing undefined error for same variable.
I am using Linux.
My Code
function init_remote_commands_to_use
{
# Test if the environment variable SSH_FOR_RCOMMANDS is present in .temip_config file,
# use secured on non secured rcommand depending on the result
if [ "$SSH_FOR_RCOMMANDS" != "" ]
then
if [ "$SSH_FOR_RCOMMANDS" = "ON" ]
then
# Check if the environment variable SSH_PATH is specified in .temip_config file
if [ "$SSH_PATH" != "" ]
then
SH_RCMD=$SSH_PATH
else
SH_RCMD=$SSH_CMD
fi
# Check if a ssh-agent is already running
if [ "$SSH_AGENT_PID" = "" ]
then
#Run ssh-agent for secured RCommands
eval `ssh-agent`
ssh-add
STARTEDBYME=YES
fi
else
if [ "$SSH_FOR_RCOMMANDS" = "OFF" ]
then
SH_RCMD=$RSH_CMD
else
echo "Please set the SSH_FOR_RCOMMANDS value to ON or OFF in the .temip_config file"
exit 1
fi
fi
else
SH_RCMD=$RSH_CMD
fi
}
below is the error:
function: Command not found.
{: Command not found.
SSH_FOR_RCOMMANDS: Undefined variable.
Please anyone suggest what I am missing?
The C Shell csh does not have functions. It does have aliases, but those are harder to write and read. For exmaple, see here: https://unix.stackexchange.com/questions/62032/error-converting-a-bash-function-to-a-csh-alias
It might be a good idea to simply switch to Bash, where your existing code may already be working.

how to declare variable name with "-" char (dash ) in linux bash script

I wrote simple script as follow
#!/bin/bash
auth_type=""
SM_Read-only="Yes"
SM_write-only="No"
echo -e ${SM_Read-only}
echo -e ${SM_Write-only}
if [ "${SM_Read-only}" == "Yes" ] && [ "${SM_Write-only}" == "Yes" ]
then
auth_type="Read Write"
else
auth_type="Read"
fi
echo -e $auth_type
And when i execute it i got following output with errors.
./script.bash: line 5: SM_Read-only=Yes: command not found
./script.bash: line 6: SM_write-only=No: command not found
only
only
Read
Any one know correct way to declare the variable with "-" (dash)?
EDIT:
have getting response from c code and evaluate the variables for example
RESP=`getValue SM_ Read-only ,Write-only 2>${ERR_DEV}`
RC=$?
eval "$RESP"
from above scripts code my c binary getValue know that script want Read-only and Write-only and return value to script.So during eval $RESP in cause error and in my script i access variable by
echo -e ${SM_Read-only}
echo -e ${SM_Write-only}
which also cause error.
Rename the variable name as follows:
SM_Read_only="Yes"
SM_write_only="No"
Please, don't use - minus sign in variable names in bash, please refer to the answer, on how to set the proper variable name in bash.
However if you generate the code, based on others output, you can simply process their output with sed:
RESP=$(getValue SM_ Read-rule,Write-rule 2>${ERR_DEV}|sed "s/-/_/g")
RC=$?
eval "$RESP"
- is not allowed in shell variable names. Only letters, numbers, and underscore, and the first character must be a letter or underscore.
I think you cant have a dash in your variables names, only letters, digits and "_"
Try:
SM_Read_only
Or
SM_ReadOnly

Is there a "goto" statement in bash?

Is there a "goto" statement in bash ? I know It is considered bad practice, but I need specifically "goto".
If you are using it to skip part of a large script for debugging (see Karl Nicoll's comment), then if false could be a good option (not sure if "false" is always available, for me it is in /bin/false):
# ... Code I want to run here ...
if false; then
# ... Code I want to skip here ...
fi
# ... I want to resume here ...
The difficulty comes in when it's time to rip out your debugging code. The "if false" construct is pretty straightforward and memorable, but how do you find the matching fi? If your editor allows you to block indent, you could indent the skipped block (then you'll want to put it back when you're done). Or a comment on the fi line, but it would have to be something you'll remember, which I suspect will be very programmer-dependent.
No, there is not; see ยง3.2.4 "Compound Commands" in the Bash Reference Manual for information about the control structures that do exist. In particular, note the mention of break and continue, which aren't as flexible as goto, but are more flexible in Bash than in some languages, and may help you achieve what you want. (Whatever it is that you want . . .)
It indeed may be useful for some debug or demonstration needs.
I found that Bob Copeland solution http://bobcopeland.com/blog/2012/10/goto-in-bash/ elegant:
#!/bin/bash
# include this boilerplate
function jumpto
{
label=$1
cmd=$(sed -n "/$label:/{:a;n;p;ba};" $0 | grep -v ':$')
eval "$cmd"
exit
}
start=${1:-"start"}
jumpto $start
start:
# your script goes here...
x=100
jumpto foo
mid:
x=101
echo "This is not printed!"
foo:
x=${x:-10}
echo x is $x
results in:
$ ./test.sh
x is 100
$ ./test.sh foo
x is 10
$ ./test.sh mid
This is not printed!
x is 101
You can use case in bash to simulate a goto:
#!/bin/bash
case bar in
foo)
echo foo
;&
bar)
echo bar
;&
*)
echo star
;;
esac
produces:
bar
star
If you're testing/debugging a bash script, and simply want to skip forwards past one or more sections of code, here is a very simple way to do it that is also very easy to find and remove later (unlike most of the methods described above).
#!/bin/bash
echo "Run this"
cat >/dev/null <<GOTO_1
echo "Don't run this"
GOTO_1
echo "Also run this"
cat >/dev/null <<GOTO_2
echo "Don't run this either"
GOTO_2
echo "Yet more code I want to run"
To put your script back to normal, just delete any lines with GOTO.
We can also prettify this solution, by adding a goto command as an alias:
#!/bin/bash
shopt -s expand_aliases
alias goto="cat >/dev/null <<"
goto GOTO_1
echo "Don't run this"
GOTO_1
echo "Run this"
goto GOTO_2
echo "Don't run this either"
GOTO_2
echo "All done"
Aliases don't usually work in bash scripts, so we need the shopt command to fix that.
If you want to be able to enable/disable your goto's, we need a little bit more:
#!/bin/bash
shopt -s expand_aliases
if [ -n "$DEBUG" ] ; then
alias goto="cat >/dev/null <<"
else
alias goto=":"
fi
goto '#GOTO_1'
echo "Don't run this"
#GOTO1
echo "Run this"
goto '#GOTO_2'
echo "Don't run this either"
#GOTO_2
echo "All done"
Then you can do export DEBUG=TRUE before running the script.
The labels are comments, so won't cause syntax errors if disable our goto's (by setting goto to the ':' no-op), but this means we need to quote them in our goto statements.
Whenever using any kind of goto solution, you need to be careful that the code you're jumping past doesn't set any variables that you rely on later - you may need to move those definitions to the top of your script, or just above one of your goto statements.
Although others have already clarified that there is no direct goto equivalent in bash (and provided the closest alternatives such as functions, loops, and break), I would like to illustrate how using a loop plus break can simulate a specific type of goto statement.
The situation where I find this the most useful is when I need to return to the beginning of a section of code if certain conditions are not met. In the example below, the while loop will run forever until ping stops dropping packets to a test IP.
#!/bin/bash
TestIP="8.8.8.8"
# Loop forever (until break is issued)
while true; do
# Do a simple test for Internet connectivity
PacketLoss=$(ping "$TestIP" -c 2 | grep -Eo "[0-9]+% packet loss" | grep -Eo "^[0-9]")
# Exit the loop if ping is no longer dropping packets
if [ "$PacketLoss" == 0 ]; then
echo "Connection restored"
break
else
echo "No connectivity"
fi
done
This solution had the following issues:
Indiscriminately removes all code lines ending in a :
Treats label: anywhere on a line as a label
Here's a fixed (shell-check clean and POSIX compatible) version:
#!/bin/sh
# GOTO for bash, based upon https://stackoverflow.com/a/31269848/5353461
goto() {
label=$1
cmd=$(sed -En "/^[[:space:]]*#[[:space:]]*$label:[[:space:]]*#/{:a;n;p;ba};" "$0")
eval "$cmd"
exit
}
start=${1:-start}
goto "$start" # GOTO start: by default
#start:# Comments can occur after labels
echo start
goto end
# skip: # Whitespace is allowed
echo this is usually skipped
# end: #
echo end
There is one more ability to achieve a desired results: command trap. It can be used to clean-up purposes for example.
There is no goto in bash.
Here is some dirty workaround using trap which jumps only backwards:)
#!/bin/bash -e
trap '
echo I am
sleep 1
echo here now.
' EXIT
echo foo
goto trap 2> /dev/null
echo bar
Output:
$ ./test.sh
foo
I am
here now.
This shouldn't be used in that way, but only for educational purposes. Here is why this works:
trap is using exception handling to achieve the change in code flow.
In this case the trap is catching anything that causes the script to EXIT. The command goto doesn't exist, and hence throws an error, which would ordinarily exit the script. This error is being caught with trap, and the 2>/dev/null hides the error message that would ordinarily be displayed.
This implementation of goto is obviously not reliable, since any non-existent command (or any other error, for that manner), would execute the same trap command. In particular, you cannot choose which label to go-to.
Basically in real scenario you don't need any goto statements, they're redundant as random calls to different places only make your code difficult to understand.
If your code is invoked many times, then consider to use loop and changing its workflow to use continue and break.
If your code repeats it-self, consider writing the function and calling it as many times as you want.
If your code needs to jump into specific section based on the variable value, then consider using case statement.
If you can separate your long code into smaller pieces, consider moving it into separate files and call them from the parent script.
I found out a way to do this using functions.
Say, for example, you have 3 choices: A, B, and C. A and Bexecute a command, but C gives you more info and takes you to the original prompt again. This can be done using functions.
Note that since the line containg function demoFunction is just setting up the function, you need to call demoFunction after that script so the function will actually run.
You can easily adapt this by writing multiple other functions and calling them if you need to "GOTO" another place in your shell script.
function demoFunction {
read -n1 -p "Pick a letter to run a command [A, B, or C for more info] " runCommand
case $runCommand in
a|A) printf "\n\tpwd being executed...\n" && pwd;;
b|B) printf "\n\tls being executed...\n" && ls;;
c|C) printf "\n\toption A runs pwd, option B runs ls\n" && demoFunction;;
esac
}
demoFunction
This is a small correction of the Judy Schmidt script put up by Hubbbitus.
Putting non-escaped labels in the script was problematic on the machine and caused it to crash. This was easy enough to resolve by adding # to escape the labels. Thanks to Alexej Magura and access_granted for their suggestions.
#!/bin/bash
# include this boilerplate
function goto {
label=$1
cmd=$(sed -n "/$#label#:/{:a;n;p;ba};" $0 | grep -v ':$')
eval "$cmd"
exit
}
start=${1:-"start"}
goto $start
#start#
echo "start"
goto bing
#boom#
echo boom
goto eof
#bang#
echo bang
goto boom
#bing#
echo bing
goto bang
#eof#
echo "the end mother-hugger..."
A simple searchable goto for the use of commenting out code blocks when debugging.
GOTO=false
if ${GOTO}; then
echo "GOTO failed"
...
fi # End of GOTO
echo "GOTO done"
Result is-> GOTO done
My idea for creating something like "goto" is to use select with case and assign a variable, which I then check in an if statement. Not perfect, but may help in some cases
Example:
#!/usr/bin/env bash
select goto in Ubuntu Debian Quit ; do
case $goto in
Ubuntu) { CHOICE="Ubuntu" ; break ; } ;;
Debian) { CHOICE="Debian" ; break ; } ;;
Quit) { echo "Bye" ; exit ; } ;;
*) { echo "Invalid selection, please try again..." ; } ;;
esac
done
if [ "$CHOICE" == "Ubuntu" ]; then
echo "I'm in Ubuntu"
fi
if [ "$CHOICE" == "Debian" ]; then
echo "I'm in Debian"
fi
Why don't anyone just use functions directly ?
BTW functions are easier to deal with than making a new thing
My style :
#!/bin/bash
# Your functions
function1 ()
{
commands
}
function2 ()
{
commands
}
:
:
functionn ()
{
commands
}
# Execute 1 to n in order
for i in {1..n}
do
function$i
done
# with conditions
for i in {1..n}
do
[ condition$i ] && function$i
done
# Random order
function1
functionn
function5
:
:
function3
Example for above style :
#!/bin/bash
# Your functions
function1 ()
{
echo "Task 1"
}
function2 ()
{
echo "Task 2"
}
function3 ()
{
echo "Task 3"
}
function1
function3
function2
Output :
Task 1
Task 3
Task 2
Drawbacks :
Script in an organized way.
Less problems and not prone to errors.
You can make function inside a existing function.
Move back and forth without any problems.

Resources