Nim use a input in arrays cannot evaluate at compile time - nim-lang

I just started working with nim a few days ago and cant figure out why I always get this error: Error: cannot evaluate at compile time: threadcount
import strutils
proc thread_test()=
echo "test"
echo "How many threads do you want to use?"
var threadcount = readLine(stdin)
echo threadcount
var threads: array[threadcount, Thread[void]]
for i in 0..high(threads):
threads[i].createThread(thread_test)
joinThreads(threads)
echo "i"

The First type argument for array must be a compile-time constant (e.g. known when the program compiles, not when it runs). So it is not possible to read size from input and use it for array - you need to have a dynamic container like seq.
There is no particular workaround for that - you can store the number of threads in const threadCount = 12, but it also has to be a compile-time constant.
With seq your code would be
import strutils
proc thread_test()=
echo "test"
echo "How many threads do you want to use?"
var threadcount = readLine(stdin)
echo threadcount
var threads: seq[Thread[void]]
for i in 0..high(threads):
threads.add createThread(thread_test)
joinThreads(threads)
echo "i"

Related

Two way communication with process

I have given some compiled program. I want to communicate with it from my bash script by program stdin and stdout. I need two way communication. Program cannot be killed between exchange of information. How I can do that?
Simple example:
Let that program be compiled partial summation (C++) and script results will be squares of that sums. Program:
int main() {
int num, sum = 0;
while(true) {
std::cin >> num;
sum += num;
std::cout << sum << std::endl;
}
}
My script should looks like that:
for i in 1 2 3 4; do
echo "$i" > program
read program to line;
echo $((line * line))
done
If in program I have for(int i = 1; i <= 4; ++i), then I can do something like that:
exec 4< <(./program); # Just read from program
for i in 1 2 3 4; do
read <&4 line;
echo "sh: $((line * line))";
done
For more look here. From the other hand, if in program I have std::cout << sum * sum;, then solution could be:
exec &3> >(./program); # Write to program
for i in 1 2 3 4; do
echo "$i" > &3
done
My problem is two way communication with other process / program. I don't have to use exec. I cannot install third party software. Bash-only solution, without files, will be nice.
If I run other process, it will be nice to know pid to kill that at the end of script.
I think about communication with two or maybe three processes in the future. Output of firs program may dependents on output of second program and also in second side. Like communicator of processes.
However, I cannot recompile programs and change something. I have only stdin and stdout communication in programs.
If you have bash which is newer than 4.0, you can use coproc.
However, don't forget that the input/output of the command you want to communicate might be buffered.
In that case you should wrap the command with something like stdbuf -i0 -o0
Reference: How to make output of any shell command unbuffered?
Here's an example
#!/bin/bash
coproc mycoproc {
./a.out # your C++ code
}
# input to "std::cin >> num;"
echo "1" >&${mycoproc[1]}
# get output from "std::cout << sum << std::endl;"
# "-t 3" means that it waits for 3 seconds
read -t 3 -u ${mycoproc[0]} var
# print it
echo $var
echo "2" >&${mycoproc[1]}
read -t 3 -u ${mycoproc[0]} var
echo $var
echo "3" >&${mycoproc[1]}
read -t 3 -u ${mycoproc[0]} var
echo $var
# you can get PID
kill $mycoproc_PID
output will be
1
3
6
If your bash is older than 4.0, using mkfifo can do the same thing like:
#!/bin/bash
mkfifo f1 f2
exec 4<> f1
exec 5<> f2
./a.out < f1 > f2 &
echo "1" >&4
read -t 3 -u 5 var
echo $var
rm f1 f2
Considering that your C++ program reads from standard output, and prints to standard output, it's easy to put it inside a simple chain of pipes:
command_that_writes_output | your_cpp_program | command_that_handle_output
In your specific case you probably need to modify the program to only handle one single input and writing one single output, and remove the loop. Because then you can do it very simple, like this:
for i in 1 2 3 4; do
result=`echo $i | ./program`
echo $((result * result))
done

regarding functions in bash

I have a general doubt regarding how to works functions in bash, let me explain, I have the next script called testscript.sh and it contains the following :
#!/bin/bash
export var="some text"
function clock {
# some arguments
echo "the variable var is [$var]"
}
$#
So when i run the script in the next way :
.
/testscript.sh clock
The value of "var" is empty unless i put inside of the function, so the question here is : is there any method to call the individually functions as I'm trying to do and all the variables outside of them i can call them inside the functions ?
thanks
I beg to differ, as per the following transcript:
pax> cat testscript.sh
#!/bin/bash
export var="some text"
function clock {
# some arguments
echo "the variable var is [$var]"
}
$#
pax> ./testscript.sh clock
the variable var is [some text]
As you can see there, the variable is very much set to the expected value. Hence, if it's coming out blank, you have an issue not related to the code you've shown us.

Conditional statement not working as expected

I am using Konsole on kubuntu 14.04.
I want to take arguments to this shell-script, and pass it to a command. The code is basically an infinite loop, and I want one of the arguments to the inner command to be increased once every 3 iterations of the loop. Ignoring the actual details, here's a gist of my code:
#!/bin/bash
ct=0
begin=$1
while :
do
echo "give: $begin as argument to the command"
#actual command
ct=$((ct+1))
if [ $ct%3==0 ]; then
begin=$(($begin+1))
fi
done
I am expecting the begin variable to be increased every 3 iterations, but it is increasing in the every iteration of the loop. What am I doing wrong?
You want to test with
if [ $(expr $cr % 3) = 0 ]; then ...
because this
[ $ct%3==0 ]
tests whether the string $ct%3==0, after parameter substitution, is not empty. A good way for understanding this is reading the manual for test and look at the semantics when it is given 1, 2, 3 or more arguments. In your original script, it only sees one argument, in mine it sees three. White space is very important in the shell. :-)
In BASH you can completely utilize ((...)) and refactor your script like this:
#!/bin/bash
ct=0
begin="$1"
while :
do
echo "give: $begin as argument to the command"
#actual command
(( ct++ % 3 == 0)) && (( begin++ ))
done

Empty Body For Loop Linux Shell

Hi I want to write and empty body loop. I just want the loop counter to increment so I want the cpu to stay busy without any IO operation. Here is what I have written but it gives me an error:
#!/bin/bash
for (( i = 0 ; i <= 1000000; i++ ))
do
done
root#ubuntu:~# ./forLoop
./forLoop: line 4: syntax error near unexpected token `done'
./forLoop: line 4: `done'
You must specify at least one command in a loop body.
The best command for such a purposes is a colon :, commonly used as a no-op shell command.
You could put a no op command inside the loop like true or false (do nothing successfully or unsuccessfully respectively).
This will be a tight loop and will burn CPU. Unless you want to warm up your computer on a cold morning, you can simply say i=1000000 and have the same effect as the loop.
What is it that you're trying to achieve?
#!/bin/bash
let i=0
while [[ $i -le 1000000 ]]; do
let i++
done
You could use sleep x if you want to delay for x number of seconds.

How can I generate new variable names on the fly in a shell script?

I'm trying to generate dynamic var names in a shell script to process a set of files with distinct names in a loop as follows:
#!/bin/bash
SAMPLE1='1-first.with.custom.name'
SAMPLE2='2-second.with.custom.name'
for (( i = 1; i <= 2; i++ ))
do
echo SAMPLE{$i}
done
I would expect the output:
1-first.with.custom.name
2-second.with.custom.name
but i got:
SAMPLE{1}
SAMPLE{2}
Is it possible generate var names in the fly?
You need to utilize Variable Indirection:
SAMPLE1='1-first.with.custom.name'
SAMPLE2='2-second.with.custom.name'
for (( i = 1; i <= 2; i++ ))
do
var="SAMPLE$i"
echo ${!var}
done
From the Bash man page, under 'Parameter Expansion':
"If the first character of parameter is an exclamation point (!), a
level of variable indirection is introduced. Bash uses the value of
the variable formed from the rest of parameter as the name of the
variable; this variable is then expanded and that value is used in the
rest of the substitution, rather than the value of parameter itself.
This is known as indirect expansion."
The Problem
You're using the value of i as if it were an array index. It isn't, because SAMPLE1 and SAMPLE2 are separate variables, not an array.
In addition, when calling echo SAMPLE{$i} you are only appending the value of i to the word "SAMPLE." The only variable you are dereferencing in this statement is $i, which is why you got the results you did.
Ways to Address the Problem
There are two main ways to address this:
Multi-stage dereferencing of an interpolated variable, via the eval builtin or indirect variable expansion.
Iterating over an array, or using i as an index into an array.
Dereferencing with eval
The easiest thing to do in this situation is to use eval:
SAMPLE1='1-first.with.custom.name'
SAMPLE2='2-second.with.custom.name'
for (( i = 1; i <= 2; i++ )); do
eval echo \$SAMPLE${i}
done
This will append the value of i to the end of the variable, and then reprocess the resulting line, expanding the interpolated variable name (e.g. SAMPLE1 or SAMPLE2).
Dereferencing with Indirect Variables
The accepted answer for this question is:
SAMPLE1='1-first.with.custom.name'
SAMPLE2='2-second.with.custom.name'
for (( i = 1; i <= 2; i++ ))
do
var="SAMPLE$i"
echo ${!var}
done
This is technically a three-step process. First, it assigns an interpolated variable name to var, then dereferences the variable name stored in var, and finally expands the result. It looks a little cleaner, and some people are more comfortable with this syntax than with eval, but the result is largely the same.
Iterating Over an Array
You can simplify both the loop and the expansion by iterating over an array instead of using variable interpolation. For example:
SAMPLE=('1-first.with.custom.name' '2-second.with.custom.name')
for i in "${SAMPLE[#]}"; do
echo "$i"
done
This has added benefits over the other methods. Specifically:
You don't need to specify a complex loop test.
You access individual array elements via the $SAMPLE[$i] syntax.
You can get the total number of elements with the ${#SAMPLE} variable expansion.
Practical Equivalency for Original Example
All three methods will work for the example given in the original question, but the array solution provides the most overall flexibility. Choose whichever one works best for the data you have on hand.
You can use eval as shown below:
SAMPLE1='1-first.with.custom.name'
SAMPLE2='2-second.with.custom.name'
for (( i = 1; i <= 2; i++ ))
do
eval echo \$SAMPLE$i
done
Not as far as I know, They way #johnshen64 said. Also, you could solve your problem using an array like so:
SAMPLE[1]='1-first.with.custom.name'
SAMPLE[2]='2-second.with.custom.name'
for (( i = 1; i <= 2; i++ )) do
echo ${SAMPLE[$i]}
done
Note that you don't need to use numbers as indexes SAMPLE[hello] will work just as well
Not a standalone answer, just an addition to Miquel's answer which I couldn't fit well in a comment.
You can populate the array using a loop, the += operator, and a here document as well:
SAMPLE=()
while read; do SAMPLE+=("$REPLY"); done <<EOF
1-first.with.custom.name
2-second.with.custom.name
EOF
In bash 4.0, it's as simple as
readarray SAMPLE <<EOF
1-first.with.custom.name
2-second.with.custom.name
EOF
eval "echo $SAMPLE${i}"

Resources