[ Gojko Vujovic @ 22.09.2004. 23:51 ] @
Program koji ćemo ovaj put pisati treba da iz liste koju daje netstat -na prikaže sledeće podatke:

broj tcp ipv4 konekcija, grupisano po stanjima (ESTABLISHED, LISTEN, TIME_WAIT, SYN_SENT, FIN_WAIT_[12], LAST_ACK i ostala koja sam možda zaboravio)

Cilj: napisati što više varijacija, bilo po efikasnosti koda i brzini izvršavanja, kriptičnosti, što manjoj dužini, ili već koji cilj sebi zacrtate.

Osnovni uslov je da se program izvršava na većini linux mašina u nekom od well known shell alata ili skripting jezika (bash, awk, sed, grep, perl, ... dozvoljene sve kombinacije) i da staje u jedan red (zato se i zove oneliner). "Red" za sada nije strogo definisan, ali mislim da je oko 100 bajtova za sada ok, možemo posle i da skraćujemo.

Kasnije ćemo zadatak proširiti nekim grupisanjem po portovima, videćemo već iz smera koji rešenja budu zauzela i naravno vaših komentara.
[ VRider @ 23.09.2004. 01:24 ] @
'Ajde da otvorim ovo:
netstat -na | grep ^tcp | awk -F\ '{ print $6 }' | uniq -c
Izvinjavam se sto nije "kripticno".
[ chupcko @ 23.09.2004. 08:27 ] @
Ajde da ubacimo malo kriptinosti :)

Code:
netstat -nat|sed -e 1,2d|tr -dc A-Z\\n|uniq -c


Sada bar mora da se manuje komanda tr (sto bi neki rekli, moja omiljena :))

P.S. videh da fali jedno _

Code:
netstat -nat|sed -e 1,2d|tr -dc A-Z_\\n|uniq -c


je malo bolje :).

[Ovu poruku je menjao chupcko dana 23.09.2004. u 13:16 GMT]
[ chupcko @ 23.09.2004. 09:20 ] @
A moze i jos sladje :)

Code:
netstat -nat|sed -e '1,2d;s/^.\{68\}//'|uniq -c


[ chupcko @ 23.09.2004. 09:37 ] @
I naravno jeste kripticno, jeste ludo, ali nije bas kratko resenje:

Code:
cat /proc/net/tcp|sed -e '1d;s/^.\{34\}\(..\).*/\1/;s/01/ESTABLISHED/;s/02/SYN_SENT/;s/03/SYN_RECV/;s/04/FIN_WAIT1/;s/05/FIN_WAIT2/;s/06/TIME_WAIT/;s/07/CLOSE/;s/08/CLOSE_WAIT/;s/09/LAST_ACK/;s/0A/LISTEN/;s/0B/CLOSING/'|uniq -c
[ Gojko Vujovic @ 23.09.2004. 10:35 ] @
Evo jednom perl, mada verovatno može i bolje, samo još malo da razmislim.. ;)

netstat -nat|perl -e '/[A-Z]{2,}/&&print"$&n"while<>'|uniq -c
[ chupcko @ 23.09.2004. 11:14 ] @
Fali jedan backslash pre n :)

A i da bi lepo radilo mora i _ da se ukljuci :)

Code:
netstat -nat|perl -e '/[A-Z_]{2,}/&&print"$&\n"while<>'|uniq -c


Eto dokaza da pratim temu :))))) hihihiih
[ Gojko Vujovic @ 23.09.2004. 11:52 ] @
Ma da pogrešan copy paste ;) hvala na ispravci.. nego sad će jedan bolji da usledi, bez uniq-a.
[ Gojko Vujovic @ 23.09.2004. 12:02 ] @
Zapravo nije, sad vidim da mi mailing lista pojede taj jedan backslash. To ćemo morati da sredimo, u međuvremenu evo grubog rešenja, još može da se doteruje:

netstat -nat|perl -e '/[A-Z_]{2,}/&&$*{$&}++while<>;for$&(keys%{*}){print$*{$&}," $&\n"}'
[ Gojko Vujovic @ 23.09.2004. 12:45 ] @
Varijacija ali još uvek bez konkretnog napretka:

netstat -nat|perl -e '/[A-Z_]{2,}/&&$*{$&}++while<>;print"$^ $*\n"while($*,$^)=each%{*}'
[ Gojko Vujovic @ 23.09.2004. 13:04 ] @
Čupko.. aj uradi brojanje u SEDu, bez uniq? :)
[ Gojko Vujovic @ 23.09.2004. 13:31 ] @
Ovo prethodno ipak nije hvatalo odvojeno FIN_WAIT_1 i FIN_WAIT_2 ali zato ovo radi:

netstat -nat|perl -e '/[A-Z_]{2,}[12]?/&&$*{$&}++while<>;@^=keys%{*};print"$*{$*=pop@^} $*\n"while$#{^}>=0'
[ chupcko @ 23.09.2004. 13:42 ] @
Paaaaaaaaaa sed tesko da moze da broji :), moralo bi da se iskoraci u awk ili perl :).
[ VRider @ 23.09.2004. 14:30 ] @
Nakon sto sam naucio nesto o netstat-u:
netstat -nat | awk -F\ '{ print $6 }' | uniq -c
Inace, imao sam ideju sa hash listom u perlu, ali, ne znam kako to da izvedem u jednom redu.
Mozda ti, Gojko, uskocis sa nekim resenjem.
[ chupcko @ 23.09.2004. 14:54 ] @
Nemoj misliti da cepidlacim :), ali evo ovo ovako radi

Code:
[chp] 1 /home/chupcko => netstat -nat | awk -F\  '{ print $6 }' | uniq -c
      1 established)
      1 Foreign
      2 LISTEN
      1 ESTABLISHED
[ VRider @ 23.09.2004. 15:05 ] @
Znam. I ja sam provalio tek posle onih prvih dva reda.
[ popeye @ 23.09.2004. 17:24 ] @
CLI verzija PHP-a:

netstat -nat | php -r 'print_r(array_count_values(preg_grep("/^[A-Z]+$/", preg_split("/[\s]+/", fread(STDIN, 5000)))));'
[ popeye @ 23.09.2004. 17:45 ] @
Mala ispravka:

netstat -nat | php -r 'print_r(array_count_values(preg_grep("/^[A-Z_]+[12]*$/", preg_split("/[\s]+/", fread(STDIN, 5000)))));'
[ bzero @ 23.09.2004. 18:25 ] @
Jedan mali Perl:

Code:

netstat -nat|perl -e '/([A-Z_]{2,}[12]*)\n/&&$u{$1}++while<>;map{print"$_-$u{$_}\n"}keys(%u);'
[ popeye @ 23.09.2004. 18:41 ] @
Bzero, to izgleda ne radi.
[ Gojko Vujovic @ 23.09.2004. 19:45 ] @
PHP resenje ne radi, popeye:


root@es:~# netstat -nat | php -r 'print_r(array_count_values(preg_grep("/^[A-Z_]+[12]*$/", preg_split("/[\s]+/", fread(STDIN, 5000)))));'
Array
(
[ESTABLISHED] => 24
[TIME_WAIT] => 37
[FIN_WAIT_1] => 1
)
root@es:~# netstat -nat|perl -e '/[A-Z_]{2,}[12]?/&&$*{$&}++while<>;@^=keys%{*};print"$*{$*=pop@^} $*\n"while$#{^}>=0'
39 LISTEN
1 UNIX
200 ESTABLISHED
37 FIN_WAIT_2
14 CLOSED
4 FIN_WAIT_1
484 TIME_WAIT
[ Gojko Vujovic @ 23.09.2004. 19:49 ] @
Evo bzero-ovog, radi na freebsd-u (perl 5.8.5):

root@es:~# netstat -nat|perl -e '/[A-Z_]{2,}[12]?/&&$*{$&}++while<>;@^=keys%{*};print"$*{$*=pop@^} $*\n"while$#{^}>=0'
1 UNIX
39 LISTEN
190 ESTABLISHED
1 LAST_ACK
14 CLOSED
32 FIN_WAIT_2
7 FIN_WAIT_1
454 TIME_WAIT
root@es:~# netstat -nat|perl -e '/([A-Z_]{2,}[12]*)\n/&&$u{$1}++while<>;map{print"$_-$u{$_}\n"}keys(%u);'
TIME_WAIT-458
FIN_WAIT_1-8
CLOSED-14
FIN_WAIT_2-33
LAST_ACK-1
ESTABLISHED-186
LISTEN-39


..ali ne i na linuxu (perl 5.8.4):

root@noc {20:48:43 - Thu Sep 23}
[ ~ ]$ netstat -nat|perl -e '/[A-Z_]{2,}[12]?/&&$*{$&}++while<>;@^=keys%{*};print"$*{$*=pop@^} $*\n"while$#{^}>=0'
8 LISTEN
17 ESTABLISHED
1 CLOSE_WAIT
1 TIME_WAIT
root@noc {20:48:52 - Thu Sep 23}
[ ~ ]$ netstat -nat|perl -e '/([A-Z_]{2,}[12]*)\n/&&$u{$1}++while<>;map{print"$_-$u{$_}\n"}keys(%u);'
ESTABLISHED-17


Ispise samo established, verovatno si i ti popeye to dobio.
[ Gojko Vujovic @ 23.09.2004. 19:51 ] @
Ali bzero, svaka cast za ideju sa map! :)
Sad sam dobio inspiraciju..
[ popeye @ 23.09.2004. 19:57 ] @
PHP kod mene na Linuxu radi:

Code:
Kerber root # netstat -nat | php -r 'print_r(array_count_values(preg_grep("/^[A-Z_]+[12]*$/", preg_split("/[\s]+/", fread(STDIN, 5000)))));'
Array
(
    [LISTEN] => 4
    [ESTABLISHED] => 31
    [CLOSE_WAIT] => 3
)
Kerber root # netstat -nat|perl -e '/[A-Z_]{2,}[12]?/&&$*{$&}++while<>;@^=keys%{*};print"$*{$*=pop@^} $*\n"while$#{^}>=0'
4 LISTEN
31 ESTABLISHED
3 CLOSE_WAIT
Kerber root #
[ Gojko Vujovic @ 23.09.2004. 20:26 ] @
Pa radi samo delimicno, verovatno te zeza ograniceni fread na 5000 bajtova.

Netstat output na opterecenijim serverima sa dosta aktivnih konekcija zna da bude MNOGO veci.

Dalje, evo iskoristih bzero-vu ideju da napravim i svoju varijantu toga, ovo mi radi i u linuxu i u bsd-u:

netstat -nat|perl -e '/[A-Z_]{2,}[12]?/&&$*{$&}++while<>;map{print"$*{$_} $_\n"}keys%{*}'
[ popeye @ 23.09.2004. 20:37 ] @
U pravu si, treba povećati dužinu.
[ alex @ 23.09.2004. 20:52 ] @
PHP resenje izlazi iz okvira postavke zadatka:


alex@home:~$ netstat -nat | php -r 'print_r(array_count_values(preg_grep("/^[A-Z_]+[12]*$/", preg_split("/[\s]+/", fread(STDIN, 5000)))));'
-bash: php: command not found
alex@home:~$


Poz,
alex.
[ popeye @ 23.09.2004. 21:17 ] @
Hehe, pa u svim većim distribucijama (Debian, Fedora, Gentoo, Mandrake...) dolazi i php-cli, te ispunjava uslov da se izvršava u nekom od skripting jezika na većini Linux mašina.

Ali ako ti tako kažeš, onda mora da je tačno. :)
[ zsteva @ 23.09.2004. 21:34 ] @
Code:

netstat -nat|perl -e'/ [A-Z]{2}.*/s&&$a{$&}++for<>;print map{$_}reverse%a;'

[ chupcko @ 23.09.2004. 22:22 ] @
Mislim kada vec krademo tudje ideje, sta ce nam map{$_} :).

Code:
netstat -nat|perl -e'/ [A-Z]{2}.*/s&&$a{$&}++for<>;print reverse%a'


Pazi kada niko nije probao sa foreach :)
[ zsteva @ 23.09.2004. 22:52 ] @
Code:

netstat -na|perl -e"/^t.{66}/&&\$a{\$'}++for<>;print reverse%a;"


rekao bih 3 karaktra krace.
[ zsteva @ 23.09.2004. 22:59 ] @
Code:

netstat -na|perl -e"/^t.{66}/&&\$a{\$'}++for<>;print reverse%a"

i josh jedan
[ zsteva @ 23.09.2004. 23:10 ] @
Code:

netstat -na|sed -e's/^t.\{67\}//;t;D'|uniq -c


hmmm... ne moze bez sort pre uniq

Code:

netstat -na|sed -e's/^t.\{67\}//;t;d'|sort|uniq -c

[ chupcko @ 24.09.2004. 08:15 ] @
U sort smo svi zaboravili :), tako nam i treba kada imamo masine sa po dve tri konekcije :)
[ B o j a n @ 24.09.2004. 08:53 ] @
Neko je pre postovao reply sa awk resenjem ( "vrider" ja mislim ) koje ima par nedostataka...

naime kod vecine awk verzija delimiter je po default-u na space karakteru
tako da kobasa od:
netstat -nat | awk -F\ '{ print $6 }' | uniq -c ( koja ujedno i ne radi )

moze stati u:
netstat -nat|awk '{print $6}'|uniq -c

sto mislim da je ujedno i najmanje zahtevno, najbrze, najrazumljivije ( ovde ide jos nekoliko superlativa )...
ne kapiram zbog cega ljudi toliko forsiraju perl i php za ovako jednostavne stvari.

[sarkazam]
jel' se prihvata resenje u C-u?
i ako da, jel' mora biti registrovan projekat na SF.net da bi se uvazio? ili jos bolje da ima sajt sa skrinshotima i cvsweb interfejsom ;)

[/sarkazam]

izvinjavam se ako sam nekome pokvario provod ovime, izacicu iz peska right away L;)


[ zsteva @ 24.09.2004. 10:56 ] @
hmm, mislim da tek ovako daje okey rezultat:
Code:

netstat -nat|awk 'NR>2{print$6}'|sort|uniq -c


ujedno to bi trebalo da bude najkrace reshenje.
[ chupcko @ 24.09.2004. 11:44 ] @
Pa nije, imam krace za jedno slovo :). nja nja :)

Code:
netstat -na|awk '/^t/{print$6}'|sort|uniq -c
[ zsteva @ 24.09.2004. 13:26 ] @
priznajem, nisam skontao da onda mogu da sklonim t iz -nat :))

kad smo kod awk-a ;)
Code:

netstat -na|awk '/^t/{a[$6]++}END{for(v in a)print v,a[v]}'


ima i awk hash array :)))
[ chupcko @ 24.09.2004. 14:07 ] @
Pa da, awk ga je prvi i uneo, sve u svemu jel ima neki novi koncept koji do sada nije vidjen ?
[ VRider @ 24.09.2004. 14:42 ] @
Moze li neko objasnjenje zasto je neophodan sort, jer vidim da ga ubacujete?
[ chupcko @ 24.09.2004. 14:53 ] @
iz man uniq:

uniq - remove duplicate lines from a sorted file

Dakle uniq zahteva sortiran ulaz:

Code:

[chp] 0 /home/chupcko => cat a
1
1
2
2
2
1
3
3
2
2
1
1
1
[chp] 0 /home/chupcko => cat a | uniq 
1
2
1
3
2
1


Dakle da netstat sortia po vrstama bilo bi ok, ali posto ne sortira, moramo mi da sortiramo.
[ zsteva @ 24.09.2004. 20:16 ] @
neshto novo, pa npr:
Code:

main(){int a=0,b=0,c=0;for(;read(0,&b,1);
b==10?a=0,c++:0)++a>68&&c>2?write(1,&b,1):0;}


pa onda:
Code:

netstat -nat|./a.out|sort|uniq -c


e sad sort i uniq ubaciti u program sazeto, to je vec izazov.
ali mislim da je bolja strategija sa direktnim brojanjem
kao kod perl varijante. ali treba implementirati sve to :))
ah da, program je samo za LITTLE_ENDIAN mashine,
zbog onog b==10...

[ chupcko @ 24.09.2004. 21:37 ] @
Evo da ti skratim malo c :)

Code:

main(a,b,c){for(a=b=c=0;read(0,&b,1);b==10
?a=0,c++:0)++a>68&&c>2&&write(1,&b,1);}
 


E sada smo malo izasli iz jedne linije, ali ajde, sto ne parsiras /proc/net/tcp ?
[ zsteva @ 24.09.2004. 22:44 ] @
Ne volim ovo kracenje sa ubacivanjem intigera u deklaraciu main()a.
ali ima alternativa, i u ovom slucaju je i kraca, prebaciti a,b,c kao
globalne variable, onda nije potrebna inicijalizacija, jer se one
automatski inicijalizuju na nulu.

necu /proc/net/tcp...

Evo uz malo truda, 4 linije C koda... sigurno moze da se skrati,
ali nemogu da mozgam :)) zadovoljan sam i ovim:
Code:

char s[10][30];int a,b,c,k[10],p,i,j,r;q(){s[i][p]=0;p=j=0;while(j<i)
if(!strcmp(s[i],s[j++]))return k[j]++;k[i++]++;}main(){for(;read(0,&b
,1);b==10?a=0,c++:9)(++a>67&&c>2)?s[i][p++]=b,(b==10?q():8):2;for(;r<
i;)printf("%6d%s",k[r++],s[r]);} /* ----------> ES #0001 by zsteva */