can't get apparently simple bash function to work [duplicate] - bash

This question already has answers here:
How do I set a variable to the output of a command in Bash?
(15 answers)
Closed 1 year ago.
#!/bin/bash
START_SLEEP_TIME=2
LOOP_SLEEP_TIME=2
OK="false"
#need to wait for another proc first
sleep $START_SLEEP_TIME
RET=
check () {
echo "---1--"
echo "---2--"
return 1
}
# isn't even called but just making sure it's not a syntax issue
finalize () {
OK="true"
}
for i in {0..100}
do
echo "check"
VAL=check
sleep $LOOP_SLEEP_TIME
done
echo "Checks terminated. $OK"
The script is supposed to do more stuff, but I am trying to strip it down to the essential to see why it is not working.
The above for me just always prints
check
check
check
after sleeping but it never prints --1-- or --2--.
The function is supposed to be doing more stuff but if I can't even get this to work there's no point.

VAL=check assigns the value check to VAL.
If you want to call the function check and assign the output from the function to VAL, make it:
VAL=$(check)
If you instead want the function's exit value, make it:
check
VAL=$?

Just call your check function, i.e. write is as a command. The returned value is then in $?.

Related

bash - Can local variable assignment return false?

Say I have the following code where is_wednesday is a function that returns 0 on Wednesdays and 1 on other days.
print_wednesday() {
is_wednesday && local WEDNESDAY="Yes!" || local WEDNESDAY="No!"
echo "Is today Wednesday? $WEDNESDAY"
}
Is there a way that assigning a value to a local variable would return 1, which in this example would result in printing Is today Wednesday? No! on a Wednesday?
Yes, a (simple, syntactically correct) local variable assignment can return false. In particular, it happens if the variable has already been declared readonly elsewhere in the code, or declared with declare -r outside of a function. This Shellcheck-clean program demonstrates the issue:
#! /bin/bash -p
readonly WEDNESDAY='No!'
function test_local_return_value
{
local WEDNESDAY='Yes!'
echo "'local' returned $?"
echo "WEDNESDAY='$WEDNESDAY'"
}
test_local_return_value
The output looks like:
...: line 7: local: WEDNESDAY: readonly variable
'local' returned 1
WEDNESDAY='No!'
This is a serious limitation of local because it means that changes elsewhere in a program can break a function that appears to be completely self-contained. I have seen this happen in practice. The problem is made worse by the fact that readonly creates a global read-only variable even if it is used in a function. readonly needs to be used very carefully. It shouldn't be used in functions (use local -r instead) and it it's best to have a naming convention that ensures readonly variable names don't clash with other variable names.
The readonly issue is covered in the Bash man page (at least for Bash version 4.4). The section on local includes: "The return status is 0 unless local is used outside a function, an invalid name is supplied, or name is a readonly variable".
Can local variable assignment return false?
The built-in local will:
return 2 when called with --help
return 2 when called with invalid -flags.
return 1 if not called inside a function
return 0 ever otherwise
(or the whole Bash process will terminate, in case of like "out of memory" errors)
Note that variable assignment (I mean, without local) will return the exit status of the last process executed. The following will print No:
true && WEDNESDAY="Yes$(false)" || WEDNESDAY="No"
echo "$WEDNESDAY"
Is there a way that assigning a value to a local variable would return 1, which in this example would result in printing Is today Wednesday? No! on a Wednesday?
No.
I would recommend:
separate local from assignment
do not use && || chain, always use if.
do not use upper case variables for local variables.
and to write the function in the following way:
print_wednesday() {
local wednesday
if is_wednesday; then
wednesday="Yes"
else
wednesday="No"
fi
echo "Is today Wednesday? $wednesday!"
}

Pass an array to a function and output each line

I was wondering if anybody could help.
I have the below code, it has an array of variables, arr, this is being passed to the method outputArray(), I require this to output each of the individual elements on their own line, when I run this code it only outputs the value of var1 and then finishes executing. The function does return a 0 or 1 (true or false) but this is functioning as expected anyway.
function outputArray() {
for i in "$#"; do
echo $i
# Condition omitted, this would manipulate data and return either 1 or 0
}
#Variable definition omitted
arr=($var1 $var2 $var3)
if outputArray "${arr[#]}"; then
echo "True"
fi
I hope this makes sense, I don't post here often so please let me know if not and I'll try again.

Call bash function on its result a given amount of times

I need to call a bash function on the output of calling it on a given argument. This process is to be repeated a prescribed amount of times. Is there a quick and elegant way to do it?
Take a look at the script below. I have tried to answer your question based on what I could understand. If this does not answer your question then try to provide me with some explanation which might help me to give you a better answer.
What I have done below is created two functions, taking output from second funtion and calling a bash function named "first".
#! /bin/bash
function first() {
echo "Print Second Function Output: " $1 # "$1" prints the argument passed by function "second"
}
function second() {
var=$(pwd)
first $var # Calling function "first" using output of funtion "second"
}
second

How to emulate returning arbitrary values from functions in bash? [duplicate]

This question already has answers here:
How to return a string value from a Bash function
(20 answers)
Closed 7 years ago.
Bash functions are just statements and they don't return values. Can anyone share best practice on writing functions that return values in bash?
Let's say I've a function that joins two strings:
function JoinStrings {
returnValue="$1$2"
}
How do I reuse this function in my code? How do I get returnValue to be returned to caller? Should I just use it as a global after this function call? That leads to many errors with global variables everywhere... How to achieve code reuse in bash?
You can use echo to "return" an arbitrary value:
join_strings() {
echo "$1$2"
}
cat="cat"
dog="dog"
catdog=$(join_strings $cat $dog)
echo $catdog
# catdog
Just output the value.
function JoinStrings {
echo "$1$2"
}
JoinStrings a b #ab
x=$(JoinStrings a bc) #x is now abc

How to determine if code is executing as a script or function?

Can you determine at runtime if the executed code is running as a function or a script? If yes, what is the recommended method?
There is another way. nargin(...) gives an error if it is called on a script. The following short function should therefore do what you are asking for:
function result = isFunction(functionHandle)
%
% functionHandle: Can be a handle or string.
% result: Returns true or false.
% Try nargin() to determine if handle is a script:
try
nargin(functionHandle);
result = true;
catch exception
% If exception is as below, it is a script.
if (strcmp(exception.identifier, 'MATLAB:nargin:isScript'))
result = false;
else
% Else re-throw error:
throw(exception);
end
end
It might not be the most pretty way, but it works.
Regards
+1 for a very interesting question.
I can think of a way of determining that. Parse the executed m-file itself and check the first word in the first non-trivial non-comment line. If it's the function keyword, it's a function file. If it's not, it's a script.
Here's a neat one-liner:
strcmp(textread([mfilename '.m'], '%s', 1, 'commentstyle', 'matlab'), 'function')
The resulting value should be 1 if it's a function file, and 0 if it's a script.
Keep in mind that this code needs to be run from the m-file in question, and not from a separate function file, of course. If you want to make a generic function out of that (i.e one that tests any m-file), just pass the desired file name string to textread, like so:
function y = isfunction(x)
y = strcmp(textread([x '.m'], '%s', 1, 'commentstyle', 'matlab'), 'function')
To make this function more robust, you can also add error-handling code that verifies that the m-file actually exists before attempting to textread it.

Resources