Linux - NewbieThis Linux forum is for members that are new to Linux.
Just starting out and have a question?
If it is not in the man pages or the how-to's this is the place!
Notices
Welcome to LinuxQuestions.org, a friendly and active Linux Community.
You are currently viewing LQ as a guest. By joining our community you will have the ability to post topics, receive our newsletter, use the advanced search, subscribe to threads and access many other special features. Registration is quick, simple and absolutely free. Join our community today!
Note that registered members see fewer ads, and ContentLink is completely disabled once you log in.
If you have any problems with the registration process or your account login, please contact us. If you need to reset your password, click here.
Having a problem logging in? Please visit this page to clear all LQ-related cookies.
Get a virtual cloud desktop with the Linux distro that you want in less than five minutes with Shells! With over 10 pre-installed distros to choose from, the worry-free installation life is here! Whether you are a digital nomad or just looking for flexibility, Shells can put your Linux machine on the device that you want to use.
Exclusive for LQ members, get up to 45% off per month. Click here for more info.
I am trying to execute a .c program of mine through bash...
Problem is it takes two arguments (files) and am trying to use "for" loops to do it. I use the for loops to take the files (same number in both directories) and put them into arrays. I use the command "ls -1" in the "for loop" so they are sorted in such a way that they are in the same time and date order upon when the program is executed.
Here is the code:
Code:
for a in `ls -1 /analyses/data1/*_prt.txt`;
do echo $a;
done
for sfc in `ls -1 /analyses/data2/*_ht.txt`;
do
./plot_data $a $b >> log_file.log;
done
HOWEVER, $a in this case does not change with the loop. Thus, the program doesn't work.
So, I then tried:
Code:
for a in `ls -1 /analyses/data1/*_prt.txt`;
for sfc in `ls -1 /analyses/data2/*_ht.txt`;
do
./plot_data $a $b >> log_file.log;
done
But that produces the error: syntax error near unexpected token `for'. As a "do" statement must come after the for loop call.
Any ideas how to do this? Just need to run the program with the two arrays and have them both advance together.
for a in `ls -1 /analyses/data1/*_prt.txt`;
do
for sfc in `ls -1 /analyses/data2/*_ht.txt`;
do
./plot_data $a $b >> log_file.log;
done
done
Only problem I worry about is that won't it increase the outer loop and then increase the inner loop unevenly? I mean it would execute it like:
./plot_data $a[0] $b[0] >> log_file.log;
./plot_data $a[0] $b[1] >> log_file.log;
./plot_data $a[0] $b[2] >> log_file.log;
...
and so on?
As I want it to be like:
./plot_data $a[0] $b[0] >> log_file.log;
./plot_data $a[1] $b[1] >> log_file.log;
./plot_data $a[2] $b[2] >> log_file.log;
...
and so on.
That make sense (using [] to represent the elements in the array, starting at 0).
Aha, I thought you want to get all possible combinations. When it should be only one round, you can replace the path in the statement:
Code:
for FIRST in /analyses/data1/*_prt.txt; do
SECOND=$(basename $FIRST)
./plot_data $FIRST /analyses/data2/${SECOND%prt.txt}ht.txt >> log_file.log;
done
basename will strip off the path, then the suffix will be replaces. If the names are too different, but in the same order you can also fill two arrays:
Code:
FIRST=(/analyses/data1/*_prt.txt)
SECOND=(/analyses/data2/*_ht.txt)
for ((i=0;i<${#FIRST[*]};i++)); do
./plot_data $FIRST[i] $SECOND[i] >> log_file.log
done
Aha, I thought you want to get all possible combinations. When it should be only one round, you can replace the path in the statement:
Code:
for FIRST in /analyses/data1/*_prt.txt; do
SECOND=$(basename $FIRST)
./plot_data $FIRST /analyses/data2/${SECOND%prt.txt}ht.txt >> log_file.log;
done
basename will strip off the path, then the suffix will be replaces. If the names are too different, but in the same order you can also fill two arrays:
Code:
FIRST=(/analyses/data1/*_prt.txt)
SECOND=(/analyses/data2/*_ht.txt)
for ((i=0;i<${#FIRST[*]};i++)); do
./plot_data $FIRST[i] $SECOND[i] >> log_file.log
done
No worries... The files do have different notation, so the second way may be the way to go.. I am going to try that.
I guess though, what does: #FIRST[*] mean? I am guessing the number of elements in the array? total?
When they have different names: do they have the same order? I mean: you might end up with different and wrong combinations otherwise.
Yeah, they are in the same order and have the same number of the files... That is why I used the ls -1 to ensure that they would be paired togather... can I use that still in:
If the names are too different, but in the same order you can also fill two arrays:
Code:
FIRST=(/analyses/data1/*_prt.txt)
SECOND=(/analyses/data2/*_ht.txt)
for ((i=0;i<${#FIRST[*]};i++)); do
./plot_data $FIRST[i] $SECOND[i] >> log_file.log
done
It seems in the second way that: $SECOND[i] is getting parsed with the [i], which throws off the program... Any idea why? could it be because only FIRST is referenced when the for loop is started?
for ((i=0;i<${#FIRST[*]};i++)); do
./plot_data ${FIRST[i]} ${SECOND[i]} >> log_file.log
done
There's a more convenient way to do this.
Code:
for i in ${!FIRST[*]}; do
./plot_data ${FIRST[i]} ${SECOND[i]} >> log_file.log
done
${!array[*]} and ${!array[@]} expand to a list of the index elements of the array. This makes it a snap to loop through them, and be sure that you only get elements that actually exist.
As for using ls to set an array, you need do this:
The array is set to one element per "word" that exists inside the parentheses. So you have to use a command substitution to generate that list.
It's still not advisable nor necessary to use ls though. If the files are there, then simple globbing should generate exactly the same list as ls does.
Last edited by David the H.; 05-01-2011 at 02:55 PM.
Reason: fixed brackets
It seems in the second way that: $SECOND[i] is getting parsed with the [i], which throws off the program... Any idea why? could it be because only FIRST is referenced when the for loop is started?
Actully, both [i] are getting passed in...
I believe they need ${FIRST[i]} to be used this way... Does that sound right? or else [i] gets added to the end...
for ((i=0;i<${#FIRST[*]};i++)); do
./plot_data ${FIRST[i]} ${SECOND[i]} >> log_file.log
done
There's a more convenient way to do this.
Code:
for i in ${!FIRST[*]}; do
./plot_data ${FIRST[i]} ${SECOND[i]} >> log_file.log
done
${!array[*]} and ${!array[@]} expand to a list of the index elements of the array. This makes it a snap to loop through them, and be sure that you only get elements that actually exist.
As for using ls to set an array, you need do this:
The array is set to one element per "word" that exists inside the parentheses. So you have to use a command substitution to generate that list.
It's still not advisable nor necessary to use ls though. If the files are there, then simple globbing should generate exactly the same list as ls does.
Could you elaborate on "expand to a list of the index elements of the array".
Does that mean the for loops knows the filenames in the array?
LinuxQuestions.org is looking for people interested in writing
Editorials, Articles, Reviews, and more. If you'd like to contribute
content, let us know.