Calling external script in matlab and capturing output - bash

Hey so I have a bash command that echos a string based on reading some file. Say for simplicity it is like this
for line in `cat file`
do
if [ "$line" == "IwantThisLine" ]
then
echo "True"
fi
done
And I have it saved as its own individual script. Its called readRef.sh. So now I want to call it in matlab and store whatever it outputs in a variable! I am not entirely sure on how to do that, I seem to get an error when using evalc() on a system(). But it could be just me messing up quotations.
I tried something like
evalc(system(['./readRef.sh ' bamfile']))
The "bamfile" is a variable that is just a string to the path of a bamfile.
I get this error.
>> tes = evalc(system(['./readRef.sh ' smplBamFile]))
hg18
??? Undefined function or method 'evalc' for input arguments of type 'double'.
Coincidentally it does spit out "hg18" which is what I want to set the matlab variable to be.

Oh, I see. I don't think you need evalc at all. Reading the system docs you can just do:
[status, result] = system('echo True; echo "I got a loverly bunch of coconuts"')
And result will be
True
I got a loverly bunch of coconuts
So just do:
[status, result] = system(['./readRef.sh ' smplBamFile])
The reason evalc isn't working is that it requires its input to be a Matlab expression in a string, but you are passing it the result of system.
You could try:
evalc("system(['./readRef.sh ' smplBamFile])")
See how I'm passing in the system(...) as a string?

The reason you get this error is because system(...) returns the return-code of the command it ran, not its output. To capture its output, use
[~, output] = system(...)
tes = evalc(output);

Related

Why am I getting a leading sing quote in this echo?

I am trying to debug a bash shell script where I am trying to surround a string/variable with single quotes. I am seeing the following results and am stumped on how to debug this. It obviously has something to do with the content of the variable. I thought the variable may be an array hence some of the echo statements. IN_JSON is being constructed via calls to "jq" to construct some JSON.
echo "IN_JSON = ${IN_JSON}"
echo "IN_JSON = ${IN_JSON[*]}"
echo "IN_JSON = '${IN_JSON[*]}'"
echo "IN_JSON = '" ${IN_JSON} "'"
echo "${#IN_JSON[#]}"
Output:
IN_JSON = {"name":"RX-CLAIM-FILLED"}
IN_JSON = {"name":"RX-CLAIM-FILLED"}
'N_JSON = '{"name":"RX-CLAIM-FILLED"}
'_JSON = ' {"name":"RX-CLAIM-FILLED"}
1
What's going on here and how do I troubleshoot this? It obviously has something to do with the contents of IN_JSON, but I'm not sure why or what is going on here.
The expansion of ${IN_JSON[*]} contains a carriage return character that resets the position of the cursor to beginning of the line, so that the next character ' is printed on beginning of the line.
Most probably, you want to run your file via dos2unix.

syntax error when assigning to command result to variable

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
}

Comparing result, input and output of tests in shell

Basically what I want to do is write a shellscript that will run series of test, take in any input (if there is any) and compare the test result with an output.
So my file looks something like this.
#!/bin/sh
# Let's set our working directory
DIR="./tests"
# And create some variables
passed=0
failed=0
totalamount=0
returned=0
# Inform the user about start of testing
echo "========= TESTING INITIALIZED ========="
# Actual testing I'm trying to do
So I assume first thing I should do is create a loop that will run through the tests
for file in "./tests/1/*.test do
So Now I'm unsure how can I compare the output of my .test file with a prepared .output program.
For example, I have a program test1.test, that will calculate 2+3. The result is 5. What I want is to have this value stored and compare it with my test1.output
Any idea how to do this?
In the end I'll just compare the two values
if [ $returned -eq $expected ]; then
echo "Test was succesful"
else
echo "Test was unsuccesful"
fi
Basically the end result should look something like:
Test: test1.test
Expected result: X
Your result: Y
Test was succesful/unsuccesful
You could use diff to compare the test result with the output expected. If they match, then you could assume the test was successful. For example:
test1check="$(diff /folder/test1 /folder/test1-expected)"
if [ -z "$test1check" ]; then
echo "Test was succesful"
else
echo "Test was unsuccesful, difference on results: $test1check"
fi
If the user is going to make inputs, or in other cases at your discretion, you could run the same comparison but ignore case differences (ex: "APPLE" would match "apple"), by changing the first line like this:
test1check="$(diff -i /folder/test1 /folder/test1-expected)"
One more thing: keep in mind that this code is sensitive to newlines, so if the test result does not end in a new line and the expected result does, the script will point out the difference.

Can a string be returned from a Bash function without using echo or global variables?

I'm returning to a lot of Bash scripting at my work, and I'm rusty.
Is there a way to return a local value string from a function without making it global or using echo? I want the function to be able to interact with the user via screen, but also pass a return value to a variable without something like export return_value="return string". The printf command seems to respond exactly like echo.
For example:
function myfunc() {
[somecommand] "This appears only on the screen"
echo "Return string"
}
# return_value=$(myfunc)
This appears only on the screen
# echo $return_value
Return string
No. Bash doesn't return anything other than a numeric exit status from a function. Your choices are:
Set a non-local variable inside the function.
Use echo, printf, or similar to provide output. That output can then be assigned outside the function using command substitution.
To make it appear only in screen, you can redirect echo to stderr:
echo "This appears only on the screen" >&2
Obviously, stderr should not be redirected.
A creative use of the eval function, you can also assign values to a parameters location, and effectively to your argument, within the body of a function. This is sometimes termed a "call-by-output" parameter.
foo() {
local input="$1";
# local output=$2; # need to use $2 in scope...
eval "${2}=\"Hello, ${input} World!\""
}
foo "Call by Output" output;
echo $output;

Bash Function is not getting called, unless I echo the return value

In my program I am trying to return a value from a function, the return value is string. Everything works fine(atleast some part), if I echo the value once it is returned, but it is not even calling the function, if I dont return.... Consider the code below....
#!/bin/bash
function get_last_name() {
echo "Get Last Name"
ipath=$1
IFS='/'
set $ipath
for item
do
last=$item
done
echo $last
}
main() {
path='/var/lib/iscsi/ifaces/iface0'
current=$(get_last_name "$path")
echo -n "Current="
echo $current
}
main
It gives me an output like this
OUTPUT
Current=Get Last Name iface0
If I comment the echo $current, then the I am not even seeing the "Get Last Name", which makes to come to conclusion, that it is not even calling the function. Please let me know what mistake I am making. But one thing I am sure, bash is the ugliest language I have ever seen.......
Functions do not have return values in bash. When you write
current=$(get_last_name "$path")
you are not assigning a return value to current. You are capturing the standard output of get_last_name (written using the echo command) and assigning it to current. That's why you don't see "Get last name"; that text does not make it to the terminal, but is stored in current.
Detailed explanation
Let's walk through get_last_name first (with some slight modifications to simplify the explanation):
function get_last_name () {
ipath=$1
local IFS='/'
set $ipath
for item
do
last=$item
done
echo "Get Last Name"
echo $last
}
I added the local command before IFS so that the change is confined to the body of get_last_name, and I moved the first echo to the end to emphasize the similarity between the two echo statements. When get_last_name is called, it processes its single argument (a string containing a file path), then echoes two strings: "Get Last Name" and the final component of the file path. If you were to run execute this function from the command line, it would appear something like this:
$ get_last_name /foo/bar/baz
Get Last Name
baz
The exit code of the function would be the exit code of the last command executed, in this case echo $last. This will be 0 as long as the write succeeds (which it almost certainly will).
Now, we look at the function main, which calls get_last_name:
main() {
path='/var/lib/iscsi/ifaces/iface0'
current=$(get_last_name "$path")
echo -n "Current="
echo $current
}
Just like with get_last_name, main will not have a return value; it will produce an exit code which is the exit code of echo $current. The function begins by calling get_last_name inside a command substitution ($(...)), which will capture all the standard output from get_last_name and treat it as a string.
DIGRESSION
Note the difference between the following:
current=$(get_last_name "$path")
sets the value of current to the accumulated standard output of get_last_name. (Among other things, newlines in the output are replaced with spaces, but the full explanation of how whitespace is handled is a topic for another day). This has nothing to do with return values; remember, the exit code (the closet thing bash has to "return values") is a single integer.
current=get_last_name "$path"
would not even call get_last_name. It would interpret "$path" as the name of a command and try to execute it. That command would have a variable current with the string value "get_last_name" in its environment.
The point being, get_last_name doesn't "return" anything that you can assign to a variable. It has an exit code, and it can write to standard output. The $(...) construct lets you capture that output as a string, which you can then (among other things) assign to a variable.
Back to main
Once the value of current is set to the output generated by get_last_name, we execute
two last echo statements to write to standard output again. The first writes "Current=" without a newline, so that the next echo statement produces text on the same line as the first. The second just echoes the value of current.
When you commented out the last echo of main, you didn't stop get_last_name from being executed (it had already been executed). Rather, you just didn't print the contents of the current variable, where the output of get_last_name was placed rather than on the terminal.

Resources