syntax error when assigning to command result to variable - bash

I'm doing some basic unit testing with the shunit2 unit test framework.
I'm getting the error " syntax error near unexpected token `nodeError=$( node "node_fake_returns/return_error.js" )" on the first line of my function. the function is as follows:
function testHandleNodeReturnError{
nodeError=$( node "./node_fake_returns/return_error.js" )
if [ grep -i "Error" <<< "$nodeError" ]; then
assertTrue "true"
fi
}
It is suppose to run a node script that returns an error message to stdout, then assign that output to a variable. Only this first line in the function is important.
I'm quite new to bash and I've messed with the formatting of this line, mostly just adding spaces in different places, but I can't seem to find what's causing the syntax error. This is probably pretty simple but if somebody could show me what might be wrong I would be greatful.
Thanks!

By pasting your code to shellcheck I was left with:
function testHandleNodeReturnError{
^-- SC1095: You need a space or linefeed between the function name and body.
Which is quite literal. You need a space there.
function testHandleNodeReturnError
Using function keyword is deprecated. Just use function_name() { function_body; }.
if [ grep -i "Error" <<< "$nodeError" ]; then
This is very wrong. This is outputting the content of nodeError variable to standard input of [ command. The [ is a command, a executable, just like grep, it's an alias to test program. Then it runs [ comamnd with grep, -i, "Error" and ] as 4 of it's arguments. You don't want that. If you want to check for Error string, just use grep's exit status:
So do:
testHandleNodeReturnError() {
nodeError=$(node "./node_fake_returns/return_error.js")
if grep -q -i "Error" <<<"$nodeError"; then
assertTrue "true"
fi
}

Related

How to give a text file into a shell function?

Hi I'm trying to make a function which should get a text file and then do some things on it and then echo. But when I try to execute it, it says syntax error near unexpected token `"$cat"'
#!/bin/usr/bash
cat=$(< cat_dialogue.txt)
function test_cat (){
echo $1
}
test_cat($cat)
desired output:
>meow meow
Your program may look like the following. Note all differences. Check your scripts with shellcheck.
#!/usr/bin/env bash
cat=$(< cat_dialogue.txt)
test_cat() {
echo "$1"
}
test_cat "$cat"
Here is an example BASH function that strips a branchname:
#create function
function strip () {
#create local variable that takes input and fills $TEXT
local TEXT=$1
#stips the branch number from the branchname
echo $TEXT | sed 's/-[0-9]*//2'
}
strip "testbranch-12345-28796"
hope it helps :) also check the BASH documentation as mentioned by #joshmeranda

less: filter out pattern passed as command line argument + follow file via bash function

I'm trying to create a bash function that will use less to apply a pattern and follow the file using the argument passed to the function
my_less_function() {
if [ -z "$1" ]
then
# if no arg
less +F /var/log/my.log
else
# else, filter out the arg
less +$'&!'$1'\nF' /var/log/my.log
fi
}
my issue is that i can't get the arg to substitute properly in the else block
my_less_function MY_VALUE displays Non-match &/MY_VALUE\nF in less
it looks like it's concatenating the argument and \nF, but \nF is supposed to trigger the follow command instead of being interpreted as part of the argument
any ideas?
wrong : less +$'&!'$1'\nF' /var/log/my.log
right : less +$'&!'${1}$'\nF' /var/log/my.log

Bash prompt multiple command substitution

I am setting up my bash prompt in .bashrc using the following (simplified) function:
set_prompts() {
PS1="\u#\h in \w "
PS1+="\$(get_git_repo_details)"
PS1+="\n"
PS1+="\$(exit_status_prompt)"
}
Now the exit_status_prompt prints a different coloured prompt character, depending on whether the value of $? is 0 or not.
What I noticed though, is that with the code as above, the colour of the prompt character never updates. However, if I append the output of exit_status_prompt to $PS1 before I append the output of get_git_repo_details, or don't append the output of get_git_repo_details at all, then it does update.
Does anyone know what is causing this? Thanks.
Edit:
exit_status_prompt()
{
if [ $? -ne 0 ]
then
highlight 1 "❯ "
else
highlight 2 "❯ "
fi
}
The highlight function then just uses tput to prepend the string in the second parameter with the colour specified in the first parameter.
You need to call exit_status_prompt before doing anything else in set_prompts, or $? is going to be reset. Presumably, exit_status_prompt uses the exit status of the most recently executed command or assignment.
set_prompts() {
esp=$(exit_status_prompt)
PS1="\u#\h in \w "
PS1+="$(get_git_repo_details)"
PS1+="\n"
PS1+="$esp"
}
I've unescaped the command substitutions, because I assume that you are (and should be) running set_prompts as the first command in PROMPT_COMMAND.

Evaluate variable in if statement

So I have an array like:
al_ap_version=('ap_version' '[[ $data -ne $version ]]')
And the condition gets evaluated inside a loop like:
for alert in alert_list; do
data=$(tail -1 somefile)
condition=$(eval echo \${$alert[1]})
if eval "$condition" ; then
echo SomeAlert
fi
done
Whilst this generally works with many scenarios, if $data returns something like "-/-" or "4.2.9", I get errors as it doesn't seem to like complex strings in the variable.
Obviously I can't enclose the variable in single quotes as it won't expand so I'm after any ideas to expand the $data variable (or indeed the $version var which suffers the same possible fate) in a way that the evaluation can handle?
Ignoring the fact that eval is probably super dangerous to use here (unless the data in somefile is controlled by you and only you), there are a few issues to fix in your example code.
In your for loop, alert_list needs to be $alert_list.
Also, as pointed out by #choroba, you should be using != instead of -ne since your input isn't always an integer.
Finally, while debugging, you can add set -x to the top of your script, or add -x to the end of your shebang line to enable verbose output (helps to determine how bash is expanding your variables).
This works for me:
#!/bin/bash -x
data=2.2
version=1
al_ap_version=('ap_version' '[[ $data != $version ]]')
alert_list='al_ap_version'
for alert in $alert_list; do
condition=$(eval echo \${$alert[1]})
if eval "$condition"; then
echo "alert"
fi
done
You could try a more functional approach, even though bash is only just barely capable of such things. On the whole, it is usually a lot easier to pack an action to be executed into a bash function and refer to it with the name of the function, than to try to maintain the action as a string to be evaluated.
But first, the use of an array of names of arrays is awkward. Let's get rid of it.
It's not clear to me the point of element 0, ap_version, in the array al_ap_version but I suppose it has something to do with error messages. If the order of alert processing isn't important, you could replace the list of names of arrays with a single associative array:
declare -A alert_list
alert_list[ap_version]=... # see below
alert_list[os_dsk]=...
and then process them with:
for alert_name in ${!alert_list[#]}; do
alert=${alert_list[$alert_name]}
...
done
Having done that, we can get rid of the eval, with its consequent ugly necessity for juggling quotes, by creating a bash function for each alert:
check_ap_version() {
(($version != $1))
}
Edit: It seems that $1 is not necessarily numeric, so it would be better to use a non-numeric comparison, although exact version match might not be what you're after either. So perhaps it would be better to use:
check_ap_version() {
[[ $version != $1 ]]
}
Note the convention that the first argument of the function is the data value.
Now we can insert the name of the function into the alert array, and call it indirectly in the loop:
declare -A alert_list
alert_list[ap_version]=check_ap_version
alert_list[os_dsk]=check_op_dsk
check_alerts() {
local alert_name alert
local data=$(tail -1 somefile)
for alert_name in ${!alert_list[#]}; do
alert=${alert_list[$alert_name]}
if $alert "$data"; then
signal_alert $alert_name
fi
done
}
If you're prepared to be more disciplined about the function names, you can avoid the associative array, and thereby process the alerts in order. Suppose, for example, that every function has the name check_<alert_name>. Then the above could be:
alert_list=(ap_version os_dsk)
check_alerts() {
local alert_name
local data=$(tail -1 somefile)
for alert_name in $alert_list[#]; do
if check_$alert_name "$data"; then
signal_alert $alert_name
fi
done
}

AIX - bash script

I'm trying to implement a small bash script in AIX, but I'm having some problems. Bellow you can find a example. I have another question, if I want to add the script to Crontab, I think I'll have problems to call serverStatus.sh from IBM, how can avoid this problem.
#!/usr/bin/sh
WAS_HOME="/usr/IBM/WebSphere/AppServer/profiles/bpmnprd01/"
function StatusCheck()
{
$WAS_HOME/bin/serverStatus.sh BPM.AppTarget.bpmnprd01.0 -username admin -password admin
status=$(cat /usr/IBM/WebSphere/AppServer/profiles/bpmnprd01/logs/BPM.AppTarget.xxxxx/serverStatus.log| awk '{ if (NF > 0) { last = $NF } } END { print last }' "$#")
text="STOPPED"
if [[ $text == $status ]]
then
echo "OK"
else
echo "NOK"
fi
}
function start()
{
StatusCheck
}
start
-----------------------
when I try to execute the script above, I get the following error:
[root#bpmnprd01]/root/health_check# ./servers_check.sh
./servers_check.sh[7]: 0403-057 Syntax error at line 7 : `(' is not expected.
...after this I search on google, and I found some examples without "()" on subroutine.But I got this:
[root#bpmnprd01]/root/health_check# ./servers_check.sh
./servers_check.sh[30]: 0403-057 Syntax error at line 33 : `StatusCheck' is not expected.
Thanks in Advance
Tiago
AIX has a true bourne shell living in /bin/sh, not sure about /usr/bin/sh, but would expect that to be Bourne shell as well.
Change your script heading line (the #shebang!) to
#!/usr/bin/bash
Or the result of which bash
IHTH
You are using bash specific syntax but calling the script with sh, which has more limited capabilities. Since you want to use sh, you can use a tool like checkbashisms or shellcheck to help uncover non-portable syntax.
The immediate problem is that function foo() { ..; } is not a POSIX compliant function definition, and you should drop the keyword function and use just foo() { ..; }.
Your shell may also be lacking [[ ]] in which case you should use [ ] instead, with = instead of ==.

Resources