33
#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.

4 Answers 4

33

This works in bash:

while read line; do  
  ARRAY[$c]="$line"
  c=$((c+1))  
done < <(tcpdump -n -r "$pcap")
Sign up to request clarification or add additional context in comments.

4 Comments

Yes. It works in Bash. Any reason why it won't run in /bin/sh? I would like to make the script portable. Is portability usually important? To ensure others can also run the script...
The <(...) process substitution syntax is not available to sh.
Arrays are also not available to sh. But +1 for the process substitution.
@DW. Didn't know array's aren't supported in sh. That doesn't bode well.
30

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

4 Comments

I had high hopes for this one, but it doesn't generate the HTML files! I can't understand why. >>stackoverflow.pastebin.com/TecWxMwW
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)
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.
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 like in this answer.
2

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  

1 Comment

In the shell version, you need to set IFS to a only a newline so that the output of tcpdump is not broken at each space.
1
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.

2 Comments

You'll need to do saveIFS=$IFS; IFS=$'\n'; your-for-loop; IFS=$saveIFS since IFS causes things to be broken on spaces, tabs and newlines by default.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.