LinuxQuestions.org
Visit Jeremy's Blog.
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices

Reply
 
Search this Thread
Old 02-05-2013, 09:29 AM   #1
Hoxygen232
LQ Newbie
 
Registered: Jan 2013
Posts: 28

Rep: Reputation: Disabled
bash and c - 2 processes in concurrency to write a file


Hi,

I made a C program, it forks 2 processes and each one of them uses
Code:
system()
to call 2 scripts (script1.sh and script2.sh), what I want to do is let them write in a file (output.txt) in parallel but in different moments.
For now my script1.sh (from process P1) write in the file for first, and then script2.sh (from process P2) write in the same file, but I need them to write in this way:
Code:
time 1: P1 writes 2 words in "output.txt"
time 2: P2 wirtes 3 words in "output.txt"
time 3: P1 writes 1 word in "output.txt"
time 4: P2 writes 6 words in "output.txt"
etc...
I know that
Code:
system()
function is synchronous, but I succeeded in making it asynchronous using
Code:
system("script1.sh &")
The problem is that I don't know how to do that, because if P1 calls script1.sh with "&" it executes during P2 without pauses, so that's not what I want.
I also know how to stop P1 using
Code:
pkill -f "script1.sh
, so maybe it helps I don't know.

How can I reach that aim?
Thanks

edited at the bottom:

Last edited by Hoxygen232; 02-05-2013 at 03:17 PM.
 
Old 02-05-2013, 11:37 AM   #2
NevemTeve
Senior Member
 
Registered: Oct 2011
Location: Budapest
Distribution: Debian/GNU/Linux, AIX
Posts: 1,724

Rep: Reputation: 488Reputation: 488Reputation: 488Reputation: 488Reputation: 488
Try this:

script1:
Code:
while true; do
    echo -n 'something ' >>file.txt
    sleep 1;
done;
script2:
Code:
while true; do
    echo -n 'something else ' >>file.txt
    sleep 1;
done;
 
Old 02-05-2013, 11:58 AM   #3
Hoxygen232
LQ Newbie
 
Registered: Jan 2013
Posts: 28

Original Poster
Rep: Reputation: Disabled
ok and from the c programm do I have to call this 2 scripts with system("name.sh") or system("name.sh &")?

The problem is that if I call these 2 scripts with
Code:
system("script1.sh &")
system("script2.sh &")
I don't have a way to say to C program when to stop them, I mean that I tried to call them in that way, but in my program every script is called by a process (fork), so if child1 calls script1 and script2:
Code:
system("script1.sh &")
system("script2.sh &")
there is no way to terminate them just during child1 is alive, infact I wrote:
Code:
                   printf("\nSCRIPT called by child1:\n");
                         system("bash script1.sh &");
                         system("bash script2.sh &");
                         sleep(2);
                         child1_termination=0;
                         exit(child1_termination);
but it doesn't work because the keep running also after child1 has finished and obviously my program does other things after child1 like forking more childs, so it's not good.

Last edited by Hoxygen232; 02-05-2013 at 12:21 PM.
 
Old 02-05-2013, 03:15 PM   #4
Hoxygen232
LQ Newbie
 
Registered: Jan 2013
Posts: 28

Original Poster
Rep: Reputation: Disabled
I will explain it better:

This is what I need: I made a C program, it forks 2 childs: P1, P2 I also made some bash scripts.

I need P1 to run script1.sh, and P2 to run script2.sh. At the moment I'm using the function
Code:
system("script_name.sh")
or
Code:
system("script_name &")
to make it asynchronous, I don't know if it's the right choice because for now they don't work as I want. Btw:

script1.sh does this:
Code:
# it search a word in a dictionary and write in a file the exact line in which that 
# word is in the dictionary, i.e. word="a" is in position "1" so 
# it will write "1" in the first line of file.

 while read line; 
 do 
 sleep 1
     TRASFORMATA=$( echo "$line" | tr "[:upper:]" "[:lower:]" | sed -e 's/ //g' )  
     echo "WORDS TO SEARCH IN DICTIONARY : $TRASFORMATA:" 
     WORD=$( fgrep -w -i "$TRASFORMATA" "$dictfile" )  # got from dictionary
     echo $WORD 
  if [ -z "$WORD" ]  ## if it's not in dictionary
  then
     echo "$WORD not found!" 
     echo 
  else              
     echo "Word and relative line found.........."
##### if found, it write the relative line to a file #####
     LINE1=$( fgrep -w -n "$WORD" "$dictfile" | sed s/:$WORD//g )   
     echo "$LINE1" >> "$FILE_OUTPUT"       
  fi
 done < "$FILE_INPUT"
script2.sh does this:
Code:
# delete lines starting with letter 'z' FROM SAME FILE THAT USES script1.sh
sleep 1
while true;
do
sleep 2
echo "DELETING WORDS "
sed -i '/^z/d' "$FILE_OUTPUT"
done
They work on the SAME file (.txt). What I want is to run them at the same moment and they have to work by turns, I mean that after P! has read the first line with its script1, P2 has to run its script2, same with second line, third line, etc...

How can I do this from C program? The important thing is that every process runs one script, and these scripts has to be executed in parallel alternating them. In this way I reach my aim that is to let 2 processes to produce one output together in order to allowa one third process to read that output and work on it!

I hope it's clear

Thanks for your help
 
Old 02-05-2013, 03:50 PM   #5
mina86
Member
 
Registered: Aug 2008
Distribution: Slackware
Posts: 374

Rep: Reputation: 150Reputation: 150
Your code examples are way too long for me to even bother to read, so I'll rephrase the problem hoping that that's what you need.

Having a file “input.txt” with the following content:
Code:
line 1
line 2
line 3
line 4
a shell script “script-1.sh” with the following content:
Code:
#!/bin/sh
while read line; do
  echo "script-1 says: $line"
done
and a shell script “script-2.sh” with the following content:
Code:
#!/bin/sh
while read line; do
  echo "script-2 says: $line"
done
you want a C program which will execute both script and the resulting output will be:
Code:
script-1 says: line 1
script-2 says: line 2
script-1 says: line 3
script-2 says: line 4
than the C program has to
  • use “pipe()” system call twice to create two anonymous pipes, than
  • use “fork()” system call to fork twice with each child using one of the pipes (see “pipe” man page for example),
  • have each child use “dup2()” system call to make the reading end of the pipe their standard input (file descriptor 0),
  • have each child use “exec()” system call to execute respective script,
  • read “input.txt” file in a loop line by line sending odd lines to the first pipe and even lines to the second pipe, and
  • once the input file is finished, close pipes and exit.

If, on the other hand, your problem is that having a script “script-1.sh” with the following content:
Code:
#!/bin/sh
for i in 1 2; do echo "script-1 say $i"; done
and a script “script-2.sh” with the following content:
Code:
#!/bin/sh
for i in 1 2; do echo "script-2 say $i"; done
you need a C program that will run both scripts and the result will be:
Code:
script-1 says 1
script-2 says 1
script-1 says 2
script-2 says 1
than the C program has to
  • use “pipe()” system call twice to create two anonymous pipes, than
  • use “fork()” system call to fork twice with each child using one of the pipes (see “pipe” man page for example),
  • have each child use “dup2()” system call to make the writing end of the pipe their standard output (file descriptor 1),
  • have each child use “exec()” system call to execute respective script,
  • in a loop read a line from the first pipe and than from the second pipe each time writing them to standard output, and
  • once data in both pipes is done (you need to handle situation where one script produces different number of lines), close them and exit.

Last edited by mina86; 02-05-2013 at 03:58 PM.
 
2 members found this post helpful.
Old 02-05-2013, 04:10 PM   #6
Hoxygen232
LQ Newbie
 
Registered: Jan 2013
Posts: 28

Original Poster
Rep: Reputation: Disabled
that's great and I think that it's what I need, the problem is that I don't know those function and I don't know how to put them together :/
For example I don't know about sharing pipes from bash to C or from C to bash (maybe I did'nt understand your answer).
Btw thanks because that's what I need to do.
Maybe I could give you my code to understand how to do those steps on my code:
Code:
switch(child1=fork()) {
    case -1:    /// father
            perror("FORK failed");
            uscita=1;
            exit(uscita);                 
    case 0:     /// child1
            sleep(1);
            printf("child 1: \n");
            sleep(1);
                         printf("\nSCRIPT called by child1:\n");
                         system("bash script1.sh");
            printf("\n");
            sleep(2);
             child1_termination=0;
             exit(child1_termination);

    default:   /// child1's father
            printf("father: I have created child1.\n");
            printf("father: I'm waiting child1 termination before fork child2\n");
            wait (&child1_termination); // waiting for child1
//-----------------------------------------------------------------------------

//-----------------------------------------------------------------------------
                                        /*Fork to create child2*/
                        switch(child2=fork()) {
                                case -1:    /// father
                                        perror("second FORK failed");
                                        uscita=1;
                                        exit(uscita);

                                case 0:     /// child2
                                        printf("child2: child2\n");
                                        sleep(2);
                                            printf("\nSCRIPT called by child2:\n");
                                            system("bash script2.sh");
                                        printf("\n");
                                        sleep(2);
                                        child2_termination=0;
                                        exit(child2_termination);

                                default:   /// father
                                        printf("father:   I have created child2.\n");
                                        printf("father: I'm waiting child2 termination before fork child3\n");
                                        wait (&child2_termination);  //waiting for child2
                                        printf("father: Child2 has terminated running\n");

Last edited by Hoxygen232; 02-05-2013 at 04:21 PM.
 
Old 02-05-2013, 04:17 PM   #7
mina86
Member
 
Registered: Aug 2008
Distribution: Slackware
Posts: 374

Rep: Reputation: 150Reputation: 150
Quote:
Originally Posted by Hoxygen232 View Post
that's great and I think that it's what I need, the problem is that I don't know those function and I don't know how to put them together :/
There's man page for each of the function.
Quote:
Originally Posted by Hoxygen232 View Post
For example I don't know about sharing pipes from bash to C or from C to bash (maybe I did'nt understand your answer).
Shell script does not need to be aware of the pipes at all. Since the child will redirect the proper pipe end to its standard input/output (depending which scenario you need), the script will just read/write data to its standard input/output.
 
1 members found this post helpful.
Old 02-06-2013, 03:13 AM   #8
Hoxygen232
LQ Newbie
 
Registered: Jan 2013
Posts: 28

Original Poster
Rep: Reputation: Disabled
thanks for your replies, the problem is that understanding this from zero is very difficult for me and I'm not english :/
Could you please make an example on my code just to understand something. the are also my scripts up here in order to see what they do.

Thanks
 
Old 02-06-2013, 10:40 AM   #9
mina86
Member
 
Registered: Aug 2008
Distribution: Slackware
Posts: 374

Rep: Reputation: 150Reputation: 150
pipe man page has a nice example of how to use pipe, so for starters compile it and start playing with it.

First, change it so that child uses execl() to call the script instead of doing anything by itself. Example usage may be found in execve man page. For your use case, it seems that you'll be interested in calling execl("./script1.sh", "./script1.sh", (char *)0);.

Second, change it so that instead of writing argument to the pipe it copies standard input to the process. With that, you can further change it so that it prints some message after writing each line.

If you need to read output from the script and not write to it, than reverse the direction.

With that, it should be not that hard to create another child and write/read data to/from one and than the other.
 
1 members found this post helpful.
Old 02-06-2013, 12:05 PM   #10
millgates
Member
 
Registered: Feb 2009
Location: 192.168.x.x
Distribution: Slackware
Posts: 651

Rep: Reputation: 269Reputation: 269Reputation: 269
I have read this thread several times, but I'm still confused.
1) What are you trying to do in the first place?
2) Why do you need one C program and two shell scripts to do it?

If I understand it correctly (which I most likely don't), you have one input file and two scripts, such that

Code:
[ INPUTFILE ] ----> [ script1 ( LOOP ) ] ----> [ OUTPUTFILE1 ]

[ INPUTFILE ] ----> [ script2 ( LOOP ) ] ----> [ OUTPUTFILE2 ]
but you want to write their output into the same file, and synchronized so that one line is written by script1, then another one by script2, and the next one by script1, and so on.

Code:
                                 ,--> [ script1 ( LOOP ) ] -.
[ INPUTFILE ] ----> [ program ] -+                          +--> [ OUTPUTFILE ]
                                 `--> [ script2 ( LOOP ) ] -'
This seems pretty strange to me. I mean in one step, you construct a loop in a script, only to have to break it into pieces further up in your program? First, why don't you just put the loop where it has a point

Code:
                                          ,--> [ script1 ( one line per call ) ] -.
[ INPUTFILE ] ----> [ program ( LOOP ) ] -+                                       +--> [ OUTPUTFILE ]
                                          `--> [ script2 ( one line per call ) ] -'
Or, just write a single program/script that does all the work.

Also, reading your code from the post #4, please note that you cannot have one process write into a file and sed -i with it in the same time and expect to get anything reasonable.
 
1 members found this post helpful.
Old 02-06-2013, 01:24 PM   #11
Hoxygen232
LQ Newbie
 
Registered: Jan 2013
Posts: 28

Original Poster
Rep: Reputation: Disabled
thanks to everybody, I'll work on that.
 
  


Reply


Thread Tools Search this Thread
Search this Thread:

Advanced Search

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
how to read and write a file shared by two or more processes. Joaquin Programming 9 12-11-2012 08:30 PM
[SOLVED] How write a literal bash command in a bash file? xeon123 Linux - Newbie 6 11-29-2010 12:05 PM
[SOLVED] Bash, when I read sort write md5 file, the writen file have a space missing peter1234 Linux - General 3 09-21-2010 09:04 AM
Bash - is it possible to write to memory rather than a file basildon Linux - Newbie 7 09-24-2008 12:07 PM
best way to write a dynamic conf file in bash dkrysak Linux - General 6 02-13-2007 12:49 PM


All times are GMT -5. The time now is 10:47 AM.

Main Menu
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
identi.ca: @linuxquestions
Facebook: linuxquestions Google+: linuxquestions
Open Source Consulting | Domain Registration