How can I pass different numbers to a function in Bash script? - bash

I have a function named myfunction.C which takes a number as input. I want to have a Bash script to iterate through numbers 0 to 99 in my function.
I had this code working before, but now it passes {0..99} instead of just one number to myfunction. What is wrong here?
for i in {0..99}
do
root -b -q -l myfunction.C++\($i\)
done
exit 0

Make sure you're actually using bash to run this script, either by explicitly doing it:
bash myScript.sh
or by using a shebang line, first line in the script:
#!/usr/bin/env bash
If, for some reason you don't have bash available to you, "lesser" shells can generally call of the external seq program to do something similar, something like:
for i in $(seq 1 12) ; do echo $i ; done

Related

Returning a value from called shell script to calling perl script

I have a shell script (say test.sh), which has the following content:
var1=$(sshpass -p pass ssh user#host "cd folder1; ./test.sh $1 $2;")
echo $var1
I can see it running and returning two values (-1 and 0). Now I am calling it from a perl file:
my $ssh=system("./Test.sh $arg1 $arg2");
But here I can see that only value is being displayed is 0. -1 is not being displayed. Can anyone please help?
I gather that the output of test.sh is a string 0 or -1, since exit values from scripts can't be negative. And you use Perl's system() function if you want to execute a command and don't want to capture its output.
Try instead:
my $ssh=`./Test.sh $arg1 $arg2`;

Shell Script: Passing each line as an argument to another script

Good day.
At work i have a script that receives a number as an argument and it shows me some information related to that number as an output.
The thing is some times i receive a huge list of numbers and executing this script numerous times during the day takes a lot of my time.
I would like to know if there is a way to save all those numbers on a file and direct each line of said file to be executed by the script.
Lets say my file contains the following numbers:
999999999
888888888
777777777
666666666
555555555
and the script is executed as follows:
sh script.sh 55(Number) go
Thanks in advance.
Assuming your inputs are in input.txt, a simple while read loop will do:
while read -r line <&3; do
sh script.sh "55${line}" go
done 3<input.txt
See BashFAQ #1 for discussion of this technique.
A few notes:
sh script.sh is actually very poor form: It ignores the shebang line in that script, such that it can no longer specify its own interpreter. It's much better to run ./script.sh after making your script executable; that way if it has #!/usr/bin/env bash or #!/usr/bin/ksh or any other shebang that will be honored, so you don't risk causing your script to fail by running it with a POSIX sh interpreter when it was written for a more capable shell language.
The 3<input.txt puts the input file on descriptor 3, rather than the default <input.txt redirection of using stdin; using an alternate file descriptor number ensures that your script can read from the user (prompting from stdin), if it wants to.
One way to accomplish that is using xargs, for example:
xargs -I{} sh script.sh 55{} go < numbers.txt
This assumes that you put your numbers in a file named numbers.txt.
For each line in the file, the {} in sh script.sh 55{} go will be replaced with the value in the line.
For example:
xargs -I{} echo number is: {} < input
Given your sample input, the above will produce:
number is: 999999999
number is: 888888888
number is: 777777777
number is: 666666666
number is: 555555555

Bash: increment a variable from a script every time when I run that script

I want that a variable from a script to be incremented every time when I run that script. Something like this:
#!/bin/bash
n=0 #the variable that I want to be incremented
next_n=$[$n+1]
sed -i "2s/.*/n=$next_n/" ${0}
echo $n
will do the job, but is not so good if I will add other lines to the script before the line in which the variable is set and I forget to update the line sed -i "2s/.*/n=$next_n/" ${0}.
Also I prefer to not use another file in which to keep the variable value.
Some other idea?
#!/bin/bash
n=0;#the variable that I want to be incremented
next_n=$[$n+1]
sed -i "/#the variable that I want to be incremented$/s/=.*#/=$next_n;#/" ${0}
echo $n
A script is run in a subshell, which means its variables are forgotten once the script ends and are not propagated to the parent shell which called it. To run a command list in the current shell, you could either source the script, or write a function. In such a script, plain
(( n++ ))
would work - but only when called from the same shell. If the script should work from different shells, or even after switching the machine off and on again, saving the value in a file is the simplest and best option. It might be easier, though, to store the variable value in a different file, not the script itself:
[[ -f saved_value ]] || echo 0 > saved_value
n=$(< saved_value)
echo $(( n + 1 )) > saved_value
Changing the script when it runs might have strange consequences, especially when you change the size of the script (which might happen at 9 → 10).

How can my Bash script see a loop variable inside a command line argument?

I can't seem to "access" the value of my loop variable when executing a command line argument in a Bash script. I'd like to be able to write something like
#!/bin/bash
for myvar in 1 2 3
do
$#
done
and run the script as ./myscript echo "${myvar}".
When I do this, the lines are echoed as empty. I probably don't have a firm grasp one exactly what's being evaluated where.
Is what I want even possible?
$myvar is evaluated before the child script is even run, so it can't be evaluated within.
That is, when you invoke your script as:
./myscript echo "${myvar}"
what is actually being called is:
./myscript echo ''
presuming that $myvar is empty in the enclosing environment.
If you wanted to be evil (and this is evil, and will create bugs, and you should not do it), you could use eval:
#!/bin/bash
for myvar in 1 2 3; do
eval "$1"
done
...and then call as:
./myscript 'echo "${myvar}"'
Something less awful would be to export a variable:
#!/bin/bash
export myvar
for myvar in 1 2 3; do
"$#"
done
...but even then, the way you call the script will need to avoid preevaluation. For instance, this will work in conjunction with the above:
./myscript bash -c 'echo "$myvar"'
...but that basically has you back to eval. On the other hand:
./myscript ./otherscript
...will do what you want, presuming that otherscript refers to $myvar somewhere within. (This need not be a shell script, or even a script; it can be an executable or other command, and it will still be able to find myvar in the environment).
What's the real goal (ie. business purpose) you're trying to achieve? There's probably a way to accomplish it better aligned with best practices.

Is it possible to get the exit code from a subshell?

Let's imagine I have a bash script, where I call this:
bash -c "some_command"
do something with code of some_command here
Is it possible to obtain the code of some_command? I'm not executing some_command directly in the shell running the script because I don't want to alter it's environment.
$? will contain the return code of some_command just as usual.
Of course it might also contain a code from bash, in case something went wrong before your command could even be executed (wrong filename, whatnot).
Here's an illustration of $? and the parenthesis subshell mentioned by Paggas and Matti:
$ (exit a); echo $?
-bash: exit: a: numeric argument required
255
$ (exit 33); echo $?
33
In the first case, the code is a Bash error and in the second case it's the exit code of exit.
You can use the $? variable, check out the bash documentation for this, it stores the exit status of the last command.
Also, you might want to check out the bracket-style command blocks of bash (e.g. comm1 && (comm2 || comm3) && comm4), they are always executed in a subshell thus not altering the current environment, and are more powerful as well!
EDIT: For instance, when using ()-style blocks as compared to bash -c 'command', you don't have to worry about escaping any argument strings with spaces, or any other special shell syntax. You directly use the shell syntax, it's a normal part of the rest of the code.

Resources