LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Linux - General (http://www.linuxquestions.org/questions/linux-general-1/)
-   -   bash syntax: looping through a comma-separated list (http://www.linuxquestions.org/questions/linux-general-1/bash-syntax-looping-through-a-comma-separated-list-582122/)

David the H. 09-04-2007 11:32 AM

bash syntax: looping through a comma-separated list
 
How can I get bash to read a list of inputs one at a time?

I'm trying to process some video and I would like to run the same command at predetermined intervals on the file. I'd like to use a comma-delineated list of timestamps as the input. I want to do something like this:

for TIME in "time1,time2,time3,time4" ; do command @ $TIME ; done

But I can't figure out how to get bash to process such a list. I tried looking at the 'read' command, but I even figure out exactly what it's supposed to do, or whether it would apply in this case. I've found a way to input the times via a text file (using the 'line' command), but it's a big hassle since I have to edit the list so that there's one entry per line. There must be a way to use the list as-is. I've searched this forum and this web but haven't found anything useful.

I want to be able to do this both from the command prompt and eventually through an actual script. Can someone help me out here?


PS: As a related question, is there any easy way to generate a list of regularly spaced timestamps, say every 300 seconds, with the format "hh:mm:ss"?

nx5000 09-04-2007 11:51 AM

Something like that?

1)
IFS=","
var="a,b,c"

for v in $var
do echo "$v"
done

2)

while /bin/true; do sleep 300; date +"%H:%M:%S"; done

colucix 09-04-2007 11:56 AM

Quote:

Originally Posted by David the H. (Post 2880929)
I've found a way to input the times via a text file (using the 'line' command), but it's a big hassle since I have to edit the list so that there's one entry per line.

This can be done as in
Code:

> echo a,b,c,d | sed s/,/\\n/g
a
b
c
d


unSpawn 09-04-2007 12:35 PM

...and with a default IFS "for v in ${var//,/ }"?

David the H. 09-04-2007 12:45 PM

Quote:

Originally Posted by nx5000 (Post 2880950)
Something like that?

1)
IFS=","
var="a,b,c"

for v in $var
do echo "$v"
done

Ok, this seems to work. I had to look up what IFS is. Interesting. But it still seems a bit sloppy though. Wouldn't I have to manually unset the ISF variable after I finished with it, or risk having it interfere with other shell uses? Is there no way to feed the list in directly, without having to resort to a variable or file?
Quote:

2)

while /bin/true; do sleep 300; date +"%H:%M:%S"; done
This doesn't seem to do what I want. This generates a list of real-time timestamps. I just want to create a count of 5 minute intervals from 00:00:00 up to, say 01:30:00 (for example).

@colucix: Thank you. That does make converting the list between formats easier. But I'd still like to avoid having to use a text file altogether.

David the H. 09-04-2007 12:51 PM

unSpawn, I just tried your string, but that doesn't seem to work. It only removes the commas, concatenating all the values together into a single long one.

colucix 09-04-2007 02:17 PM

Quote:

Originally Posted by David the H. (Post 2881030)
I just want to create a count of 5 minute intervals from 00:00:00 up to, say 01:30:00 (for example).

To generate a list of times, I'd suggest to use a while loop, and increase time accordingly to the choosen timestep, like this:
Code:

#/bin/bash
# --------------------------------------------------
#  Initialize counter
# --------------------------------------------------
min=0

# --------------------------------------------------
#  Loop from 0 to 90 every 5 minutes
# --------------------------------------------------
while [ $min -le 90 ] ; do

    time=`date -d "00:00:00 $min minutes" +%H:%M:%S`
   
    echo $time
   
    min=$((min + 5))

done

The date command in linux is very flexible and let to output any date (not only "now") absolute or relative. See info date for details. Cheers!

rch1231 09-04-2007 06:32 PM

Based on your original question here are a couple of ideas:

The shell for command looks for white space between entries and you could use this for example:

for x in time1 time2 time3 do ; <script> ; done

or you can put the entries in a file and have linux execute a shell command to read the file. For example if you have a list of the times in a file called dotimes and you want the for statement to read the list you could use the back quote (just to the left of the 1 key).

for x in `cat dotimes` do ; <script> ; done

as a bash script you could call it would look like this:

#!/bin/bash
for x in `cat /home/me/dotimes`
do
<script>
done

But the simplest way I can think of to do something like what you want is to run a simple loop with the sleep command. Say you want to list the contents of the /var/tmp directory every 5 minutes to see if the file is growing. From the command line you would type the following:

while true
do
date
/bin/ls -la /var/tmp
sleep 300
done

The command would run every 5 minutes till you stop (break AKA <CTRL> C) it. It would list the date at the beginning of each run so you could see the time change.

Hope this helps.
rhoward1231@yahoo.com

nx5000 09-05-2007 04:50 AM

Quote:

Wouldn't I have to manually unset the ISF variable after I finished with it, or risk having it interfere with other shell uses?
If you put the code I posted _in a script_ (and not directly in your current shell) then as a normal script, bash will create a new subshell, execute the script and then return to the parent shell. Then nothing is kept.
If you do it from the command line then yes, you have to set it back,maybe like this:
old_IFS=${IFS}
blabah
IFS=${old_IFS}

Well, it's not that tricky I think. Otherwise unSpawn method is shorter but you need to be using bash, it's not POSIX compliant.

Code:

$ echo $0
/bin/bash

$ var="a,b,c" ; for v in ${var//,/ }; do echo $v; done
a
b
c

$ /bin/sh

$ echo $0
/bin/sh

$var="a,b,c" ; for v in ${var//,/ }; do echo $v; done
/bin/sh: Syntax error: Bad substitution


unSpawn 09-05-2007 11:50 AM

Quote:

Originally Posted by David the H. (Post 2881039)
unSpawn, I just tried your string, but that doesn't seem to work. It only removes the commas, concatenating all the values together into a single long one.

Hmm, maybe you didn't add the space after the slash or you're not using Bash?

David the H. 09-06-2007 10:23 AM

Thanks for the advice everyone. Sorry I couldn't get back to you for a couple of days. There's a lot I have to reply to.

colucix: Now that appears to do just what I was looking for. A bit of modification to add some user inputs and that script will be perfect for generating various lists of timestamps.

rch1231: A-ha, I see. So it's the comma separation that's doing it. The reason I've been using commas is because that's how all the dvd authoring programs handle their chapter lists, and I've just been copy/pasting the numbers. But now I can generate my own lists or use the IFS setting or unSpawn's method to work around it. Speaking of which...

unSpawn: You were right, I did miss the space. It's always the little typos that get you, isn't it? It works when I type it in correctly. I'll probably go with that, since I don't have to worry about setting external variables that way.

nx5000: That's what I thought. I want to be able to do this both with a script and quick-&-dirty manually, so I want to be careful about the IFS setting when I'm doing the latter. And no worries about compatibility. I'll only be using bash.

I appreciate all the help. Now to implement what I've learned.


All times are GMT -5. The time now is 01:07 AM.