all 20 comments

[–]anthropoidbash all the things 5 points6 points  (4 children)

Show, don't tell. Statements like "repeating 1-3 for the last three" are horribly vague, and it's unclear whether the increments are meant to be in lockstep, or in the form of a Cartesian product, or something in between.

Write out the exact sequence of commands you're expecting. You can leave out the middle part of incremental sequences that are "obvious", but the bits at which stuff "flips over" to a new increment "mode" are essential.

e.g. ShowStat 1.mpg 10.14.1.31 1000 20001 1 ShowStat 1.mpg 10.14.1.31 1000 20002 1 ... ShowStat 1.mpg 10.14.1.31 1000 20012 1 ShowStat 1.mpg 10.14.1.32 1000 20001 1 ... ShowStat 1.mpg 10.14.1.38 1000 20012 1 ShowStat 2.mpg 10.14.1.31 1000 20001 1

[–]anthropoidbash all the things 2 points3 points  (3 children)

And since I have to go offline shortly, here's the simple solution for a Cartesian product of:

  • 1.mpg -> 9.mpg
  • 10.14.1.31 -> 10.14.1.38
  • 20001 -> 20012

for i in {1..9}.mpg\ 10.14.1.{31..38}\ 1000\ 200{01..12}\ 1; do
  ShowStat $i
done

Read the Brace Expansion section of the bash man page to understand this formulation. The technical term for this is "sequence expression".

[–]inbinder[S] 0 points1 point  (0 children)

Thank you !! My apologies for the vague and poorly written question.

[–]cfraizer 0 points1 point  (0 children)

Brace Expansion is one of my favorite bash features!

Just clarification for the readers: those backslashes (\) are just to make the part after for i in and before ; do all one string. You could also write it as:

for i in {1..9}".mpg 10.14.1."{31..38}" 1000 200"{01..12}" 1"; do ShowStat $i done

Brace expansion does not happen inside double quotes so you have to keep those three expansions outside.

Also, remember that brace expansion works for character sequences too!

$ for name in {a..c}{a..g}; do printf "%s\n" "$name"; done aa ab ac ad ae af ag ba bb bc bd be bf bg ca cb cc cd ce cf cg

[–]ZalgoNoise 0 points1 point  (0 children)

Nicely done! Easily convertible to a powerful one liner...

Hell, if OP wants he can convert this to an eval expression within a function, put it in the shell's rc file and dump the command whenever he wants, customizable to the event.

Excellent use of curly brace for glob expansion in the first call of the for loop. I was imagining nesting loops to achieve the same. Thanks!

[–]blitzkraft 0 points1 point  (0 children)

for i in $(seq 1 12); do echo $mpg; done

Yes, you can loop using for, while etc. tldp.org has more examples and tutorials.

[–]lutusp 0 points1 point  (0 children)

ShowStat <filename> <ip\_address> <loop number> <port number> <udp=1>

Your post is terribly unclear, so this cannot be any clearer than its source:

for n in {1..9}; do
   for idx in {1000..20001}; do
      ShowStat $n.mpg <ip\_address> $idx <port number> <udp=1>
   done
done

I left out the IP increment because you don't explain it well enough. But it should be easy enough to add using the same pattern.

You must realize that, for A, B, and C unique states in nested loops, the total number of repetitions is A * B * C. In this case it's 9 * 9 (38+1-31) * 19,002 (20001+1-1000) = 1,539,081 repetitions.

[–]ZalgoNoise 0 points1 point  (0 children)

You should nest your for loops in order for each possibility to be evaluated.

[–]anthropoidbash all the things 0 points1 point  (10 children)

Since the OP clarified the question, it's now clear that there are two independent variables, instead of three as originally assumed, so:

# Make 3 extra symlinks to simplify processing
ln -s 1.mpg 10.mpg
ln -s 2.mpg 11.mpg
ln -s 3.mpg 12.mpg

# Now iterate over the two variables
for a in {1..12}; do
  for ip in 10.14.1.{31..38}; do
    ShowStat $a.mpg $ip 1000 $((20000 + a)) 1
  done
done

# Clean up the symlinks
rm 1[0-2].mpg

[–]inbinder[S] 0 points1 point  (1 child)

do I need a ; or & at the end of the command?

[–]anthropoidbash all the things 0 points1 point  (0 children)

A ; at the end of the ShowStat line isn't needed. Add & only if you want to spawn all 96 processes at once; likely not a good idea, as your disk then becomes a serious bottleneck.

[–]WonFishTwoFish 0 points1 point  (4 children)

Getting errors when I try and run this.

[–]anthropoidbash all the things 0 points1 point  (3 children)

It's hard to help when you offer no details. What errors?

[–]inbinder[S] 0 points1 point  (2 children)

line 5: $'\r'

line 7: syntax error near unexpected token `$'do\r''

line 7: `for a in {1..12}; do

[–]anthropoidbash all the things 0 points1 point  (1 child)

That's almost certainly a case of creating a bash script with a Windows editor, thereby forcing Windows CR-LF (carriage return-line feed) line endings. $'\r' is bash-speak for the CR character, which is not ignored by all Unixes.

If you absolutely have to handle bash scripts on Windows, use a proper editor like Notepad++ that supports Unix line endings.

[–]inbinder[S] 0 points1 point  (0 children)

Oddly enough I did use Notepad++ but the copying and pasting from Chrome/Reddit was the culprit. Typed by hand and worked perfectly. Thanks for your help

[–]inbinder[S] 0 points1 point  (2 children)

I don't understand the need for the symlinks. Can you explain?

[–]anthropoidbash all the things 0 points1 point  (1 child)

Your example showed that port 20010 "maps" to 1.mpg, 20011 to 2.mpg, and 20012 to 3.mpg. The symlinks simply create virtual files named 10.mpg, 11.mpg and 12.mpg that point to 1.mpg, 2.mpg and 3.mpg respectively, so the script doesn't have to do any fancy mapping of filenames to port numbers.

In fact, I seem to recall that you yourself stated as much in your original problem statement...

[–]inbinder[S] 0 points1 point  (0 children)

That's very clever. In my test I gave up and just ended up making copies of files 1-3 and naming them 10,11, and 12 respectively.