29
#I used to have this, but I don't want to write to the disk
#
pcap="somefile.pcap"
tcpdump -n -r $pcap > all.txt
while read line; do  
  ARRAY[$c]="$line"
  c=$((c+1))  
done < all.txt  

The following fails to work.

# I would prefer something like...
#
pcap="somefile.pcap"
while read line; do  
  ARRAY[$c]="$line"
  c=$((c+1))  
done < $( tcpdump -n -r "$pcap" )

Too few results on Google (doesn't understand what I want to find :( ). I'd like to keep it Bourne-compatible (/bin/sh), but it doesn't have to be.

Felipe Alvarez
  • 3,720
  • 2
  • 33
  • 42

4 Answers4

31

This works in bash:

while read line; do  
  ARRAY[$c]="$line"
  c=$((c+1))  
done < <(tcpdump -n -r "$pcap")
Ignacio Vazquez-Abrams
  • 776,304
  • 153
  • 1,341
  • 1,358
28

This is sh-compatible:

tcpdump -n -r "$pcap" | while read line; do  
  # something
done

However, sh does not have arrays, so you can't have your code like it is in sh. Others are correct in saying both bash and perl are nowadays rather widespread, and you can mostly count on their being available on non-ancient systems.

UPDATE to reflect @Dennis's comment

Amadan
  • 191,408
  • 23
  • 240
  • 301
  • I had high hopes for this one, but it doesn't generate the HTML files! I can't understand why. >>http://stackoverflow.pastebin.com/TecWxMwW – Felipe Alvarez Jun 06 '10 at 08:04
  • 1
    eek, I left an "echo" inside, that I used for testing. Fixed now, should be equivalent to yours. (BTW, I assume you meant your code does not generate HTML when you insert this snippet - this snippet by itself doesn't generate HTML any more than your snippet did) – Amadan Jun 06 '10 at 08:18
  • 3
    Except that the Bourne shell doesn't have arrays. And, in Bash the two lines in the body of your loop (OK, the OP's loop) can be collapsed into: `ARRAY[$c]+=("$line")` or `ARRAY[c++]="$line"`. But +1 for the pipe into `while`. – Dennis Williamson Jun 06 '10 at 11:41
  • 3
    Note that since this uses pipes, any variables created inside the while loop won't be available once the while loop exists (because pipes create a subshell). If you're okay with something that only works in bash, you could feed in the input using [process substitution](http://mywiki.wooledge.org/ProcessSubstitution) like in [this answer](https://stackoverflow.com/a/2983261/6157047). – Galen Long Feb 04 '20 at 20:21
1

If you don't care about being bourne, you can switch to Perl:

my $pcap="somefile.pcap";
my $counter = 0;
open(TCPDUMP,"tcpdump -n -r $pcap|") || die "Can not open pipe: $!\n";
while (<TCPDUMP>) {
    # At this point, $_ points to next line of output
    chomp; # Eat newline at the end
    $array[$counter++] = $_;
}

Or in shell, use for:

for line in $(tcpdump -n -r $pcap)  
do  
 command  
done  
DVK
  • 126,886
  • 32
  • 213
  • 327
0
for line in $(tcpdump -n -r $pcap)  
do  
 command  
done 

This isn't exactly doing what I need. But it is close. And Shell compatible. I'm creating HTML tables from the tcpdump output. The for loop makes a new <tr> row for each word. It should make a new row for each line (\n ending). Paste bin script01.sh.

Felipe Alvarez
  • 3,720
  • 2
  • 33
  • 42