Monday, April 9, 2012

SA hw3

上學期 SA 的 shell script 作業

http://people.cs.nctu.edu.tw/~huanghs/course/sysadm2011/slides/hw3.pdf


hw3-1

作業是一個分析 sockstat 指令的 sh one liner

Use one-line command to show per-user socket statistic





在 apua 提示下用 awk 完成了...

sockstat | tail -n+2 | sort | awk '{print $1" "$2}' | xargs | 
awk '{split($0,a);for (i=1;i<=NF;i+=2){c[a[i]" "a[i+1]]++;}
for (i in c) {print c[i]" "i}}' | sort -k2 | xargs | 
awk '{split($0,a);for(i=1;i<=NF;i+=3){b[a[i+1]]+=a[i];c[a[i+1]]=sprintf("%s %s",c[a[i+1]],a[i+2]);}
for (i in b){printf("%s: %s (%s )\n", i, b[i],c[i]);}}' | sort -nk2 -r | 
awk -v T=$THRESHOLD '{if ($2 > T) print $0}'

http://pastie.org/2794451






一步一步分析

sockstat |                    # 這步不用說吧XD 
 
tail -n+2 |                   # 從第2行開始印 
                              # 把 USER COMMAND PID  ....  濾掉 
 
sort |                        # 對第一欄 (user) 排序 
 
awk '{print $1" "$2}' |       # 取出前兩欄 
 
xargs |                       # 把東西通通黏起來 
 
 
awk ' { 
    split($0,a);              # 東西全部裝進 a 這個 hash 裡面 
    for (i = 1; i <= NF; i += 2) { 
        c[a[i]" "a[i+1]]++;   # 把 "user process" 做為 key 並統計 
    } 
    for (i in c) { 
        print c[i]" "i        # 印出 "sum user process" 
    } 
}' | 
 
 
sort -k2 |                    # 對 user 做排序 
 
xargs |                       # 黏起來 
 
awk '{ 
    split($0,a);              # 通通裝進 a 
    for(i=1;i<=NF;i+=3){ 
        b[a[i+1]]+=a[i];      # 算出所有開啟 sock 數 
        c[a[i+1]]=sprintf("%s %s",c[a[i+1]],a[i+2]); 
                              # append 其他 process 到後面 
    } 
    for (i in b){ 
        printf("%s: %s (%s )\n", i, b[i],c[i]); 印答案出來 
    } 
}' | 
 
sort -nk2 -r |                # 降序 sort 
 
awk -v T=$THRESHOLD '{        # 處理 THRESHOLD 
    if ($2 > T) 
        print $0 
}'


===========================================

結論

    把 awk 當成 Perl 來寫就沒問題囉 ^.<







作業二是比較麻煩的 zfs Snapshot Management

然後順便玩玩 parsing 指令參數這樣






這個作業學到 logger 指令的用法、然後也更熟悉 zfs 了XD

#!/bin/sh                                                                                                                              
                                                                                                                                       
                                                                                                                                       
# get args                                                                                                                             
d=0                                                                                                                                    
count=0                                                                                                                                
while getopts f:n:c:d op                                                                                                               
do                                                                                                                                     
    case $op in                                                                                                                        
        f) fs=$OPTARG;;                                                                                                                
        n) name=$OPTARG;;                                                                                                              
        c) count=$OPTARG;;                                                                                                             
        d) d=1;;                                                                                                                       
        *) echo "TAs are so evil Q____Q"                                                                                               
           echo "Usage: sudo ./zfsSnap.sh -f <fs> -n <name> <-c <count> | -d>."                                                        
           exit 1;                                                                                                                     
           ;;                                                                                                                          
    esac                                                                                                                               
done
                                                                                                                                       
# $count should be digits and can't start by 0                                                                                         
count=`echo $count | grep -v [^0-9] | grep -v ^0`                                                                                      
                                                                                                                                       
# all args are not NULL strings                                                                                                        
if [ -z $count ] || [ -z $fs ] || [ -z $name] ; then                                                                                   
  echo "TAs are so evil Q____Q"                                                                                                        
  echo "Usage: sudo ./zfsSnap.sh -f <fs> -n <name> <-c <count> | -d>."                                                                 
  exit 1;                                                                                                                              
fi                                                                                                                                     
          
# rolling                                                                                                                              
if [ $count -gt 0 ] ; then       # i don't know how to write && in shell script :(                                                     
    if [ $d -eq 0 ] ; then                                                                                                             
                                                                                                                                       
        # list of snapshots we want                                                                                                    
        shotlist=`zfs list -r -t snapshot | cut -f1 -d' ' | tail -n+2 | grep $fs | grep $name | sort`                                  
                                                                                                                                       
        # how many lines                                                                                                               
        line=`zfs list -r -t snapshot | cut -f1 -d' ' | tail -n+2 | grep $fs | grep $name | wc -l | xargs`                             
        num=$count                                                                                                                     
                                                                                                                                       
        # need to delete something                                                                                                     
        del=1                                                                                                                          
                                                                                                                                       
        # don't need to delete                                                                                                         
        if [ $line -lt $num ] ; then                                                                                                   
          num=$line                                                                                                                    
          del=0                                                                                                                        
        fi                                                                                                                             
                                                                                                                                       
        # create $num .. 0 and store it in $num                                                                                        
        while [ $num -ge 0 ]                                                                                                           
        do                                                                                                                             
          echo $num >> QQ             # TA changed requirements, so i feel Q____Q                                                      
          num=$(( $num -1 ))                                                                                                           
        done
        done                                                                                                                           
        num=`cat QQ`                                                                                                                   
        rm QQ                                                                                                                          
                                                                                                                                       
                                                                                                                                       
        # rolling (J.K. ?)                                                                                                             
        for i in $num                                                                                                                  
        do                                                                                                                             
            old=$(( $i-1 ))                                                                                                            
            if [ $i -gt 0 ] ; then                                                                                                     
                zfs rename $fs@$name.$old $fs@$name.$i                                                                                 
                logger -p local7.notice "zfsSnap.sh [$$]: Old snapshot: $fs@$name.$old rotated"                                        
            fi                                                                                                                         
        done                                                                                                                           
                                                                                                                                       
        # kil oldest shot                                                                                                              
        if [ $del -eq 1 ] ; then                                                                                                       
          zfs destroy $fs@$name.$count                                                                                                 
          logger -p local7.notice "zfsSnap.sh [$$]: Delete snapshots: $fs@$name.$(($count - 1))"                                       
        fi                                                                                                                             
                                                                                                                                       
        # make a new one                                                                                                               
        zfs snapshot $fs@$name.0                                                                                                       
        logger -p local7.notice "zfsSnap.sh [$$]: New snapshot: $fs@$name.0"                                                           
    fi                                                                                                                                 
fi
                                                                                                                                      
# delete                                                                                                                               
if [ $d -eq 1 ] ; then                                                                                                                 
    # fine all shots and just destroy them                                                                                             
    shotlist=`zfs list -r -t snapshot | cut -f1 -d' ' | tail -n+2 | grep $fs | grep $name`                                             
    for i in $shotlist                                                                                                                 
    do                                                                                                                                 
        zfs destroy $i                                                                                                                 
        logger -p local7.notice "zfsSnap.sh [$$]: Delete snapshots: $i"                                                                
    done                                                                                                                               
fi



作業三是最好玩也是最麻煩的

RSS Feed Reader!

用 shell script 的 cdialog 做出一個 command line 底下的 RSS feed reader




為了避免麻煩,助教ㄉㄉ很 nice 的有用 Python 寫了一個 RSS parser 工具

不過我那時候還不會 Python,同時也是為了挑戰自己,用 Perl hack 了一個XD






這個 code 版本少了當初修好的 bug ...

demo 時的 code 忘記丟到哪了 orz  現在留下來的版本是後來改給 Ubuntu 的


read 功能沒有濾掉 RSS 吐給我的 XML 標籤,後還是用 sed 解決的

 sed -e 's/<[^>]*>//g'




#!/bin/sh
# welcome msg
cdialog --title "Welcome" --msgbox "Hello world!" 5 40

# main manu
menu () {

  cdialog --title "Main Menu" --menu "Choose Action" 12 45 5 \
    R "Read - read subscribed feeds" \
    S "Subscrib - new subscription" \
    D "Delete - delete subscription" \
    U "Update - update subscription" \
    Q "Bye~" 2>/tmp/menuitem
  menuitem=`cat /tmp/menuitem`
  rm /tmp/menuitem
  case $menuitem in
    R ) return 1 ;;
    S ) return 2 ;;
    D ) return 3 ;;
    U ) return 4 ;;
    Q ) return 5 ;;
  esac
}

Read () {
  cdialog --title "Read" --menu "choose subscription" 12 45 5 `cat who | awk '{print NR" "$1}'` 2>/tmp/menuitem

  menuitem=`cat /tmp/menuitem`
  rm /tmp/menuitem
  
#  cdialog --title "Read" --menu "foo" 20 45 10 `cat iamben/titles | awk '{print "\""NR"\" \""$0"\""}'` 2>/tmp/menuitem
#  menuitem=`cat /tmp/menuitem`
#  rm /tmp/menuitem
  cdialog --msgbox "$menuitem" 5 40 

}

Update () {
# i did it with a Perl script
  ./fetchRSS.pl > /dev/null
}

Subscrib () {
  cdialog --title "Subscrib" --inputbox "Enter feed url" 8 60 2>/tmp/url
  url=`cat /tmp/url`
  rm /tmp/url
  
  cdialog --title "Subscrib" --inputbox "Enter feed name" 8 60 2>/tmp/name
  name=`cat /tmp/name`
  rm /tmp/name
  
  echo $name >> who
  echo $url >> subscription
  Update
}


Delete () {
  cdialog --title "Delete" --menu "choose subscription" 12 45 5 `cat who | awk '{print NR" "$1}'` 2>/tmp/menuitem
  menuitem=`cat /tmp/menuitem`
  rm /tmp/menuitem
  rm -r $menuitem
  cat subscription | awk -v m=$menuitem '{if ( NR == m ) ; else print $0}' > s
  cat who | awk -v m=$menuitem '{if (NR == m) ; else print $0}' > w
  rm subscription
  rm who
  mv s subscription
  mv w who
}

# an infinity loop
while [ 1 ] ; do
  menu
  m=$? 
  case $m in
      1 ) Read;;
      2 ) Subscrib;;
      3 ) Delete ;;
      4 ) Update ;;
      5 ) exit 0;;
  esac
done




#!/usr/bin/perl
use strict;

use LWP::Simple;
use XML::Feed;

my @subs = ();

open SUBSCRIPTION , "subscription" or die "file subscription open error: $!";
while (<SUBSCRIPTION>) {
    chomp;
    push @subs, $_;
}

while (<*>) {
  chomp;
  if (-d $_) {
    chdir $_;
    system ("rm *");
    chdir "..";
    rmdir $_ or die "QQ:$_ $!";
  }
}

my $z = 1;
for my $sub (@subs) {
    my $feed = XML::Feed->parse(URI->new($sub))
        or die XML::Feed->errstr;
     
    mkdir $z or die "can't write directory [$z]: $!";
    chdir $z or die "can't cd to directory [$z]: $!";

    system("rm titles");
    for my $entry ($feed->entries) {
        open W, sprintf(">>titles") , or die "can't write file [$z/titles] :$!";
        print W $entry->title, "\n";
        close W;
    }

    my $count = 1;
    for my $entry ($feed->entries) {
        open W, sprintf(">%s", $count) , or die "can't write file [$z/$count] :$!";
        print W "---\n";
        print W "Title: ", $entry->title, "\n";
        print W "Link: \n  ", $entry->link, "\n";
        print W "---\n";
        print W $entry->content->body, "\n";
        $count++;
        close W;
    }
    chdir "..";
    $z++;
}

No comments:

Post a Comment