Challenge: The Phantom Bash Loop

davidktw

Arch-Supremacy Member
Joined
Apr 15, 2010
Messages
13,547
Reaction score
1,300
without using loops or recursion how to create fib seq? if i make the bash script calls itself is that considered as recursion?

The entire system is always in a loop. :)
That would depends on how the script calls itself. I would argue it is possible to do so without considered as recursion.
Otherwise any loops would be recursion since it is repeatedly running a same set of codes right ?
Here the exclusion of recursion is within the programming language construct, get it ?

:)
 

diminishin

Senior Member
Joined
Sep 12, 2013
Messages
2,105
Reaction score
1,218
The entire system is always in a loop. :)
That would depends on how the script calls itself. I would argue it is possible to do so without considered as recursion.
Otherwise any loops would be recursion since it is repeatedly running a same set of codes right ?
Here the exclusion of recursion is within the programming language construct, get it ?

:)
i tried searching bash for functions that can be used but can't really find any

anyway, here's my answer, self calling script

size=$1

if [ -z $2 ]
then
counter=0
else
counter=$2
fi

sqrt5=$(bc <<< "scale=10; sqrt(5)")

phi=$(bc <<< "scale=10; (1+$sqrt5)/2")

if [ $counter -le $size ]
then
cur=$(bc <<< "scale=10; (($phi^$counter)/$sqrt5)+0.5")
cur=$(bc <<< "scale=0; $cur/1")
echo $cur
/bin/bash ./bash_challenge_next.sh $size $[counter+1]
fi
 

davidktw

Arch-Supremacy Member
Joined
Apr 15, 2010
Messages
13,547
Reaction score
1,300
i tried searching bash for functions that can be used but can't really find any

anyway, here's my answer, self calling script

size=$1

if [ -z $2 ]
then
counter=0
else
counter=$2
fi

sqrt5=$(bc <<< "scale=10; sqrt(5)")

phi=$(bc <<< "scale=10; (1+$sqrt5)/2")

if [ $counter -le $size ]
then
cur=$(bc <<< "scale=10; (($phi^$counter)/$sqrt5)+0.5")
cur=$(bc <<< "scale=0; $cur/1")
echo $cur
/bin/bash ./bash_challenge_next.sh $size $[counter+1]
fi

Good try, but have you tried invoking it 10000 times? :)
 

davidktw

Arch-Supremacy Member
Joined
Apr 15, 2010
Messages
13,547
Reaction score
1,300
i tried searching bash for functions that can be used but can't really find any

...

The answer is understanding Unix Programming. The feature you ought to be looking for is exec

The technique was originally evolved from the earlier counting question. You have used brace expansion, and this is mine
Bash:
[[ $1 > 0 ]] && exec -c $0 $(($1 - 1)) "$1\n$2" || echo -ne "$2"

The Fibonacci solution is evolved from it too.
Bash:
[[ $1 -ge 0 ]] && N=${2:-0} M=${3:-1} && read S < <(echo "$M + $N" | bc) && echo $N && exec -c $0 $(($1 - 1)) $S $N $M

Why is it not recursion ? If you know how exec works. It basically just load an executable image file into the same process and start executing it, analogous wipe out everything in the memory and reload again. The flexible part is the means to pass information from one iteration into another via the parameters. If you look at the entire script, you can simply formulate it as a function where the script parameters are the function parameters.

Hence there you go, a solution to loop without really using any bash looping construct nor recursion. It will also work eternally as long as the computer is running since it wouldn't be consuming more and more memory extensively.

There are some issues with your code and also I'm not sure why you want to use that formula since the question is not asking you to compute one particular term but all the terms from start to end. Just dynamic programming will do. You will also want to take a look at what happens to bc output when the number is really large.

Hope you have fun.
:)
 
Last edited:

Trader11

Banned
Joined
Oct 14, 2018
Messages
15,698
Reaction score
5,233
The answer is understanding Unix Programming. The feature you ought to be looking for is exec

The technique was originally evolved from the earlier counting question. You have used brace expansion, and this is mine
Bash:
[[ $1 > 0 ]] && exec -c $0 $(($1 - 1)) "$1\n$2" || echo -ne "$2"

The Fibonacci solution is evolved from it too.
Bash:
[[ $1 -ge 0 ]] && N=${2:-0} M=${3:-1} && read S < <(echo "$M + $N" | bc) && echo $N && exec -c $0 $(($1 - 1)) $S $N $M

Why is it not recursion ? If you know how exec works. It basically just load an executable image file into the same process and start executing it, analogous wipe out everything in the memory and reload again. The flexible part is the means to pass information from one iteration into another via the parameters. If you look at the entire script, you can simply formulate it as a function where the script parameters are the function parameters.

Hence there you go, a solution to loop without really using any bash looping construct nor recursion. It will also work eternally as long as the computer is running since it wouldn't be consuming more and more memory extensively.

There are some issues with your code and also I'm not sure why you want to use that formula since the question is not asking you to compute one particular term but all the terms from start to end. Just dynamic programming will do. You will also want to take a look at what happens to bc output when the number is really large.

Hope you have fun.
:)
How did you learn these advanced Bash tecniques?

Most of the time, I use bash to run simple CI build or deployment jobs. Didn't know Bash can be so powerful to run Fibs
 

davidktw

Arch-Supremacy Member
Joined
Apr 15, 2010
Messages
13,547
Reaction score
1,300
How did you learn these advanced Bash tecniques?

Most of the time, I use bash to run simple CI build or deployment jobs. Didn't know Bash can be so powerful to run Fibs
TL;DR

I don't strive to simply complete my work, I strive to perfect my craft.

When you do that, you wouldn't be satisfy with just able to solve the problem. You will ask if there are any other better ways to do the same thing ? What is the pros and cons, caveats and quirks and workarounds you need to deal with for each solutions. That's how you improve more than just the work assigned to you. Real industrial works are good starting ground, but often they are limited by time, resources and cost. If you want to investigate further, you need to further complicate the problem. You need to look beyond the problem and investigate. That's how to improve significantly.

Honestly speaking, what I have demonstrate in this Bash challenge is nothing difficult. All the skill set requires is what is required of a Unix software engineer. exec command is found in a lot of programming languages, but be careful what you are reading. Quite a few languages don't exhibit the real exec that is happening on a Unix system. In an Unix OS course, you will learn fork() and exec() in C. Here is a tutorial on it https://ece.uwaterloo.ca/~dwharder/icsrts/Tutorials/fork_exec/
There are quite a few variants of exec but they all does the same thing. Reload the specified image into the current process. We do that in Unix C because it often follows a fork process. Fork is the Unix way of creating new processes from the current process. These new processes are children process with their parent process set as the current one. This is also the start of multiprocessing.

Just this simplistic shell code would have already demonstrated the above.
Bash:
$ ls

The current shell is first forked to create child process, then the child process run an exec command to load the binary image of ls and totally replace the forked process of bash. All these knowledge comes from understanding Unix programming.

Here is a demonstration. In one terminal, I was running this
Code:
while true; do ls; done >/dev/null

In another terminal, I am running this
Code:
$ while true; do pstree | egrep -B 2 '\bls\b' | grep -v grep; echo ------------------------------------; done
 |   |-+= 01790 root login -fp davidktw
 |   | \-+= 01792 davidktw -bash
 |   |   \--= 83082 davidktw (ls)
------------------------------------
 |   |-+= 01790 root login -fp davidktw
 |   | \-+= 01792 davidktw -bash
 |   |   \--= 83109 davidktw (ls)
------------------------------------
 |   |-+= 01790 root login -fp davidktw
 |   | \-+= 01792 davidktw -bash
 |   |   \--= 83135 davidktw (ls)
------------------------------------
------------------------------------
 |   |-+= 01790 root login -fp davidktw
 |   | \-+= 01792 davidktw -bash
 |   |   \--= 83188 davidktw (ls)
------------------------------------

Notice the ls command parent is the bash shell, and despite the ls command process id is changing all the time, the shell process id (01792) never change.

The Fibonacci demonstration is just leveraging on the dynamic programming solution of it. You can of course do it for a lot of other programming solutions, but it is not meant for actual use, because you will almost never want to write your code the way for the challenge, and rather just use a simple loop construct to complete it. I am just creating constraint to force into the usage of this technique.

If you feel this is difficult, would the 2 Quicksort techniques that I have written in another thread be any easier for you ?
Feel free to read them at https://forums.hardwarezone.com.sg/...odes-to-share-for-fun.6832706/#post-144837640
There are 2 techniques I have demonstrated, one is functional, the other is imperative and faster.
Too bad shell cannot use multithreading, which is not the same as multiprocessing. I do hope you understand the differences, because it will allow me to easily parallelise the quicksort in an efficient manner.

I hope you have also tried on the challenge questions. I set them for anyone whom is keen to learn.
:)
 

Trader11

Banned
Joined
Oct 14, 2018
Messages
15,698
Reaction score
5,233
TL;DR

I don't strive to simply complete my work, I strive to perfect my craft.

When you do that, you wouldn't be satisfy with just able to solve the problem. You will ask if there are any other better ways to do the same thing ? What is the pros and cons, caveats and quirks and workarounds you need to deal with for each solutions. That's how you improve more than just the work assigned to you. Real industrial works are good starting ground, but often they are limited by time, resources and cost. If you want to investigate further, you need to further complicate the problem. You need to look beyond the problem and investigate. That's how to improve significantly.

Honestly speaking, what I have demonstrate in this Bash challenge is nothing difficult. All the skill set requires is what is required of a Unix software engineer. exec command is found in a lot of programming languages, but be careful what you are reading. Quite a few languages don't exhibit the real exec that is happening on a Unix system. In an Unix OS course, you will learn fork() and exec() in C. Here is a tutorial on it https://ece.uwaterloo.ca/~dwharder/icsrts/Tutorials/fork_exec/
There are quite a few variants of exec but they all does the same thing. Reload the specified image into the current process. We do that in Unix C because it often follows a fork process. Fork is the Unix way of creating new processes from the current process. These new processes are children process with their parent process set as the current one. This is also the start of multiprocessing.

Just this simplistic shell code would have already demonstrated the above.
Bash:
$ ls

The current shell is first forked to create child process, then the child process run an exec command to load the binary image of ls and totally replace the forked process of bash. All these knowledge comes from understanding Unix programming.

Here is a demonstration. In one terminal, I was running this
Code:
while true; do ls; done >/dev/null

In another terminal, I am running this
Code:
$ while true; do pstree | egrep -B 2 '\bls\b' | grep -v grep; echo ------------------------------------; done
 |   |-+= 01790 root login -fp davidktw
 |   | \-+= 01792 davidktw -bash
 |   |   \--= 83082 davidktw (ls)
------------------------------------
 |   |-+= 01790 root login -fp davidktw
 |   | \-+= 01792 davidktw -bash
 |   |   \--= 83109 davidktw (ls)
------------------------------------
 |   |-+= 01790 root login -fp davidktw
 |   | \-+= 01792 davidktw -bash
 |   |   \--= 83135 davidktw (ls)
------------------------------------
------------------------------------
 |   |-+= 01790 root login -fp davidktw
 |   | \-+= 01792 davidktw -bash
 |   |   \--= 83188 davidktw (ls)
------------------------------------

Notice the ls command parent is the bash shell, and despite the ls command process id is changing all the time, the shell process id (01792) never change.

The Fibonacci demonstration is just leveraging on the dynamic programming solution of it. You can of course do it for a lot of other programming solutions, but it is not meant for actual use, because you will almost never want to write your code the way for the challenge, and rather just use a simple loop construct to complete it. I am just creating constraint to force into the usage of this technique.

If you feel this is difficult, would the 2 Quicksort techniques that I have written in another thread be any easier for you ?
Feel free to read them at https://forums.hardwarezone.com.sg/...odes-to-share-for-fun.6832706/#post-144837640
There are 2 techniques I have demonstrated, one is functional, the other is imperative and faster.
Too bad shell cannot use multithreading, which is not the same as multiprocessing. I do hope you understand the differences, because it will allow me to easily parallelise the quicksort in an efficient manner.

I hope you have also tried on the challenge questions. I set them for anyone whom is keen to learn.
:)
Your Unix programming skills are too advanced. I am still deciphering different parts of your bash script 🤓
 

davidktw

Arch-Supremacy Member
Joined
Apr 15, 2010
Messages
13,547
Reaction score
1,300
Your Unix programming skills are too advanced. I am still deciphering different parts of your bash script 🤓
Just keep doing it. I get to somewhere because I don't stop doing what I like.
A lot of people does that. At the same time, a lot of people don't.
So which group are you in ?

Feel free to ask anything that you don't know.
See I don't know everything about shell script too.
There are a lot of things about shell script which is outside of shell script, like the exec command that I just shared with you.
If I don't know I will find out and explain to you.
It will even be better that you find out for yourself.

:)
 

project_00

Master Member
Joined
Jan 3, 2007
Messages
3,052
Reaction score
1,912
For challengers who want to test themselves, try it but without using "exec" :)


databank_ackbar_01_169_55137220.jpeg


Signals.jpg

:)
 

davidktw

Arch-Supremacy Member
Joined
Apr 15, 2010
Messages
13,547
Reaction score
1,300
For challengers who want to test themselves, try it but without using "exec" :)


databank_ackbar_01_169_55137220.jpeg


Signals.jpg

:)

Using trap and env. Why not :)
But have you observe the memory consumption and how long it will run before something happens ?
 
Last edited:

project_00

Master Member
Joined
Jan 3, 2007
Messages
3,052
Reaction score
1,912
Using trap and env. Why not :)
But have you observe the memory consumption and how long it will run before something happens ?

It seems that memory will increase til it eventually segfaults. That's when N=3500~ on my machine. And it seems that trapping signals from a function and having the trap handler call the function again is still recursion.
I guess using traps and signals is a no-go then
 

davidktw

Arch-Supremacy Member
Joined
Apr 15, 2010
Messages
13,547
Reaction score
1,300
It seems that memory will increase til it eventually segfaults. That's when N=3500~ on my machine. And it seems that trapping signals from a function and having the trap handler call the function again is still recursion.
I guess using traps and signals is a no-go then
Your method will work in the following manner. Inelegant but works
Bash:
#!/usr/bin/env bash

TMPFILE=`mktemp -u`
mkfifo $TMPFILE
(
  trap 'sleep 0; kill -USR1 $$' USR1
  # read <&2 # this works, but a keypress will disturb it
  read <$TMPFILE
) &
C=$!
sleep 0
trap 'I=$(($I+1)); echo $I; sleep 0; [[ $I -lt $M ]] && kill -USR1 $C || exit' USR1
trap 'rm -f $TMPFILE; kill -9 $C' EXIT
I=0
M=${1:-10}
[[ $M -gt 0 ]] && kill -USR1 $C || exit
# read <&2 # this works, but a keypress will disturb it
read <$TMPFILE

Code:
$ ./countrap.sh 0
$ ./countrap.sh 1
1
$ ./countrap.sh 10
1
2
3
4
5
6
7
8
9
10
$ ./countrap.sh 20
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

Have fun :)
 
Last edited:

project_00

Master Member
Joined
Jan 3, 2007
Messages
3,052
Reaction score
1,912
Your method will work in the following manner. Inelegant but works
Bash:
#!/usr/bin/env bash

TMPFILE=`mktemp -u`
mkfifo $TMPFILE
(
  trap 'sleep 0; kill -USR1 $$' USR1
  # read <&2 # this works, but a keypress will disturb it
  read <$TMPFILE
) &
C=$!
sleep 0
trap 'I=$(($I+1)); echo $I; sleep 0; [[ $I -lt $M ]] && kill -USR1 $C || exit' USR1
trap 'rm -f $TMPFILE; kill -9 $C' EXIT
I=0
M=${1:-10}
[[ $M -gt 0 ]] && kill -USR1 $C || exit
# read <&2 # this works, but a keypress will disturb it
read <$TMPFILE

Code:
$ ./countrap.sh 0
$ ./countrap.sh 1
1
$ ./countrap.sh 10
1
2
3
4
5
6
7
8
9
10
$ ./countrap.sh 20
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

Have fun :)
Impressive. Some very interesting techniques shown here :)
 

peterchan75

Supremacy Member
Joined
Apr 26, 2003
Messages
6,719
Reaction score
529
Ever seen a mechanic moan and groan about a car that is designed without any thought for a maintenance mechanic. A mechanic has craw underneath vs open the bonnet in order to change the alternator. The same goes to programming. The coder has to be mindful of some dude who will be doing the maintenance or enhancement work in the future. Cryptic code under the disguise of efficiency or readability? I bet most programmer would prefer the latter in my humble opinion. :cool:
 

davidktw

Arch-Supremacy Member
Joined
Apr 15, 2010
Messages
13,547
Reaction score
1,300
Ever seen a mechanic moan and groan about a car that is designed without any thought for a maintenance mechanic. A mechanic has craw underneath vs open the bonnet in order to change the alternator. The same goes to programming. The coder has to be mindful of some dude who will be doing the maintenance or enhancement work in the future. Cryptic code under the disguise of efficiency or readability? I bet most programmer would prefer the latter in my humble opinion. :cool:
Most programmers just end up as doers. This is a humble opinion too. E=mc^2 may be short and readable, but most don't know enough of what it means.
There are mechanics that design cars because of how much they know about cars, they don't necessarily has to crawl under the car.
:)
 

peterchan75

Supremacy Member
Joined
Apr 26, 2003
Messages
6,719
Reaction score
529
Most programmers just end up as doers. This is a humble opinion too. E=mc^2 may be short and readable, but most don't know enough of what it means.
There are mechanics that design cars because of how much they know about cars, they don't necessarily has to crawl under the car.
:)
For Mazda 3, need to go underneath, and Toyota Vios from the top. ;)
I doubt do software maintenance work. You just throw them to your underlings. :oops:
 

peterchan75

Supremacy Member
Joined
Apr 26, 2003
Messages
6,719
Reaction score
529
Sure, tell that to the designer that design the cars. :)
But we don't have access to these designers which the same as maintenance coders do not have access to davidktw. My uni mate was telling me that some Wall Street big shot is ditching perl for python. Cryptic code can cause pain to those coders doing the migration work.
 

davidktw

Arch-Supremacy Member
Joined
Apr 15, 2010
Messages
13,547
Reaction score
1,300
But we don't have access to these designers which the same as maintenance coders do not have access to davidktw. My uni mate was telling me that some Wall Street big shot is ditching perl for python. Cryptic code can cause pain to those coders doing the migration work.
That's why I said most programmers are doers. You can choose to fit in, or surpass. It's your choice. You don't need access to me, you just need access to your inner-self.

一念之差
:)
 

peterchan75

Supremacy Member
Joined
Apr 26, 2003
Messages
6,719
Reaction score
529
That's why I said most programmers are doers. You can choose to fit in, or surpass. It's your choice. You don't need access to me, you just need access to your inner-self.

一念之差
:)
You will agree with me on this statement ?
Any piece software will evolve over time.

The original programmer might have left the company and someone has to take over the task of maintenance. Let alone debugging effort.
 
Important Forum Advisory Note
This forum is moderated by volunteer moderators who will react only to members' feedback on posts. Moderators are not employees or representatives of HWZ Forums. Forum members and moderators are responsible for their own posts. Please refer to our Community Guidelines and Standards and Terms and Conditions for more information.
Top