Bring back v1 from the dead
authorSiraaj Khandkar <siraaj@khandkar.net>
Thu, 17 Jan 2019 23:36:09 +0000 (18:36 -0500)
committerSiraaj Khandkar <siraaj@khandkar.net>
Thu, 17 Jan 2019 23:36:09 +0000 (18:36 -0500)
v1/bin/khatus_cpu_usage_from_proc_since_last_check [new file with mode: 0755]
v1/bin/khatus_show [new file with mode: 0755]
v1/bin/khatus_update_network [new file with mode: 0755]
v1/bin/khatus_update_weather [new file with mode: 0755]
v1/install [new file with mode: 0755]

diff --git a/v1/bin/khatus_cpu_usage_from_proc_since_last_check b/v1/bin/khatus_cpu_usage_from_proc_since_last_check
new file mode 100755 (executable)
index 0000000..e76d21d
--- /dev/null
@@ -0,0 +1,99 @@
+#! /bin/sh
+
+proc_stat_parse() {
+    proc_stat="$1"
+    n='[0-9]\+'
+    echo "$proc_stat" \
+    | grep "^cpu$n $n $n $n $n $n $n $n $n $n $n$" \
+    | awk '
+        {
+            cpu  = $1;
+            user = $2;
+            sys  = $4;
+            idle = $5;
+
+            total = user + sys + idle;
+            busy  = user + sys;
+
+            if (NR > 1) {printf " "};
+
+            out = sprintf("%s %d %d", cpu, total, busy);
+            #print out >> "cpu_usage_debug.txt";
+            printf "%s", out;
+        }
+        END {
+            #print "" >> "cpu_usage_debug.txt";
+            print "";
+        }
+        '
+}
+
+calc_delta() {
+    for proc_stat in "$1" "$2"; do
+        proc_stat_parse "$proc_stat"
+    done \
+    | awk '
+        {
+            t = NR;
+            for (i = 1; i <= (NF - 2); i += 3) {
+                cpu_count[t]++;
+                cpu_id = $i;  # For occasional debugging
+                total  = $(i + 1);
+                busy   = $(i + 2);
+                cpu[cpu_count[t], "total", t] = total;
+                cpu[cpu_count[t], "busy" , t] = busy;
+            }
+        }
+
+        END {
+            for (c=1; c<=cpu_count[2]; c++) {
+                total_1 = cpu[c, "total", 1];
+                total_2 = cpu[c, "total", 2];
+                busy_1  = cpu[c, "busy" , 1];
+                busy_2  = cpu[c, "busy" , 2];
+                total_d = total_2 - total_1;
+                busy_d  = busy_2  - busy_1;
+                percent_busy = (busy_d / total_d) * 100;
+
+                #printf(\
+                #    "c: %d, total_1: %f total_2: %f, total_d: %f\n",
+                #     c,     total_1,    total_2,     total_d \
+                #) >> "cpu_usage_debug.txt";
+                #printf(\
+                #    "c: %d, busy_1: %f busy_2: %f, busy_d: %f\n",
+                #     c,     busy_1,    busy_2,     busy_d \
+                #) >> "cpu_usage_debug.txt";
+                #printf(\
+                #    "c: %d, percent_busy: %f\n",
+                #     c, percent_busy \
+                #) >> "cpu_usage_debug.txt";
+
+                if (c > 1) {printf " "};
+                out = sprintf("%3.0f%%", percent_busy)
+                #printf "c: %d, out: %s\n", c, out >> "cpu_usage_debug.txt";
+                printf "%s", out;
+            }
+            #print "" >> "cpu_usage_debug.txt";
+            print "";
+        }
+        '
+}
+
+main() {
+    last_proc_stat="$HOME/var/run/cpu_usage_from_proc_since_last_check/last_proc_stat"
+
+    if [ ! -f "$last_proc_stat" ]
+    then
+        mkdir -p `dirname "$last_proc_stat"`
+        cat /proc/stat > "$last_proc_stat"
+        sleep 0.1
+    fi
+
+    previous=`cat $last_proc_stat`;
+    cat /proc/stat > "$last_proc_stat"
+    current=`cat $last_proc_stat`;
+
+    calc_delta "$previous" "$current"
+}
+
+main $@
diff --git a/v1/bin/khatus_show b/v1/bin/khatus_show
new file mode 100755 (executable)
index 0000000..5170492
--- /dev/null
@@ -0,0 +1,577 @@
+#! /bin/bash
+
+set -e
+
+BIN=$HOME/bin
+STATUS_DIR=$HOME/var/run/status
+STATUS_FILE__WIFI=$STATUS_DIR/wifi
+STATUS_FILE__ENERGY_NOTIFIED_BELLOW_HALF=$STATUS_DIR/notified_energy_bellow_half
+while getopts ":b:d:s:i:w:" opt
+do
+    case "$opt" in
+        b)
+            SCREEN_BRIGHTNESS_DEVICE_NAME="$OPTARG"
+            ;;
+        d)
+            DISK_IO_DEVICE="$OPTARG"
+            ;;
+        s)
+            DISK_SPACE_DEVICE="$OPTARG"
+            ;;
+        i)
+            PREFIXES_OF_INTERFACES_TO_SHOW="$OPTARG"
+            ;;
+        w)
+            WEATHER_STATION_ID="$OPTARG"
+            ;;
+        \?)
+            echo "Unknown option: $OPTARG" >&2
+            exit 1
+            ;;
+        :)
+            echo "Missing argument for option: $OPTARG" >&2
+            exit 1
+            ;;
+    esac
+done
+if [ "$SCREEN_BRIGHTNESS_DEVICE_NAME" == '' ]; then echo 'Missing -b' >&2; exit 1; fi
+if [ "$DISK_IO_DEVICE" == '' ];                then echo 'Missing -d' >&2; exit 1; fi
+if [ "$DISK_SPACE_DEVICE" == '' ];             then echo 'Missing -s' >&2; exit 1; fi
+if [ "$WEATHER_STATION_ID" == '' ];            then echo 'Missing -w' >&2; exit 1; fi
+SCREEN_BRIGHTNESS_DEVICE_PATH="/sys/class/backlight/$SCREEN_BRIGHTNESS_DEVICE_NAME"
+
+
+load=$(awk '{printf("%4.2f", $1)}' /proc/loadavg)
+
+fan=$(awk '/^speed:/ {printf "%4d", $2}' /proc/acpi/ibm/fan)
+
+#cpu=$($BIN/khatus_cpu_usage_from_proc_since_last_check)
+
+memory=$(
+    free \
+    | awk '
+        function round(n) {return int(n + 0.5)}
+
+        $1 == "Mem:" {
+            total=$2;
+            used=$3;
+            cache=$6;
+            prev_file = ENVIRON["HOME"] "/var/run/status/memory_used_percentage";
+            curr = round(used / total * 100);
+            getline prev < prev_file;
+            print curr > prev_file;
+            if (curr > prev) {
+                direction = ">";
+            } else if (curr < prev) {
+                direction = "<";
+            } else {
+                direction = "=";
+            }
+            printf("%s%d%%", direction, curr);
+        }')
+
+temp=$(awk 'NR == 1 {print $1 / 1000}' /sys/class/thermal/thermal_zone0/temp)
+
+disk_io=$(
+    awk '
+        {
+            bytes_per_sector = 512
+            bytes_per_unit   = 1024 * 1024
+
+            curr_sectors_read  = $3
+            curr_sectors_write = $7
+
+            prev_file_prefix        = ENVIRON["HOME"] "/var/run/status/disk_io"
+            prev_sectors_read_file  = prev_file_prefix "_sectors_read"
+            prev_sectors_write_file = prev_file_prefix "_sectors_write"
+
+            getline prev_sectors_read  < prev_sectors_read_file
+            getline prev_sectors_write < prev_sectors_write_file
+
+            diff_read_sectors  = (curr_sectors_read  - prev_sectors_read)
+            diff_write_sectors = (curr_sectors_write - prev_sectors_write)
+
+            diff_read_bytes  = diff_read_sectors  * bytes_per_sector
+            diff_write_bytes = diff_write_sectors * bytes_per_sector
+
+            diff_read  = diff_read_bytes  / bytes_per_unit
+            diff_write = diff_write_bytes / bytes_per_unit
+
+            print curr_sectors_read  > prev_sectors_read_file
+            print curr_sectors_write > prev_sectors_write_file
+
+            printf("%0.3f▲ %0.3f▼\n", diff_write, diff_read);
+
+        }
+        ' "/sys/block/$DISK_IO_DEVICE/stat"
+)
+
+disk=$(
+    df \
+    | awk \
+        -v disk_io="$disk_io" \
+        -v device="$DISK_SPACE_DEVICE" \
+        '
+        function round(n) {return int(n + 0.5)}
+
+        $1 == device {
+            curr_perc = $5; sub("%$", "", curr_perc);
+            prev_perc_file = ENVIRON["HOME"] "/var/run/status/disk_space_used";
+            getline prev_perc   < prev_perc_file;
+            print curr_perc > prev_perc_file;
+            if (curr_perc > prev_perc) {
+                direction = ">";
+            } else if (curr_perc < prev_perc) {
+                direction = "<";
+            } else {
+                direction = "=";
+            }
+            printf("%s[%d%% %s]", direction, curr_perc, disk_io);
+        }')
+
+# TODO: Wi-Fi status file should be a file per-wifi-device
+network=$(
+    ip -s addr \
+    | awk \
+        -v wifi_conn="$(cat $STATUS_FILE__WIFI)" \
+        -v prefixes_of_interfaces_to_show="$PREFIXES_OF_INTERFACES_TO_SHOW" \
+        '
+        BEGIN {
+            bytes_per_unit = 1024 * 1024
+        }
+
+        /^[0-9]+:/ {
+            sub(":$", "", $1)
+            sub(":$", "", $2)
+            sequence = $1
+            interface = $2
+            interfaces[sequence] = interface
+        }
+
+        /^ +inet [0-9]/ {
+            sub("/[0-9]+", "", $2)
+            addr = $2
+            addrs[interface] = addr
+        }
+
+        /^ +RX: / {transfer_direction = "r"}
+        /^ +TX: / {transfer_direction = "w"}
+
+        /^ +[0-9]+ +[0-9]+ +[0-9]+ +[0-9]+ +[0-9]+ +[0-9]+ *$/ {
+            io[interface, transfer_direction] = $1;
+        }
+
+        END {
+            for (seq=1; seq<=sequence; seq++) {
+                interface = interfaces[seq]
+                label = substr(interface, 1, 1)
+                if (addrs[interface]) {
+                    curr_read  = io[interface, "r"]
+                    curr_write = io[interface, "w"]
+
+                    prefix = ENVIRON["HOME"] "/var/run/status/io_net_" interface
+                    prev_read_file  = prefix "_read"
+                    prev_write_file = prefix "_write"
+
+                    getline prev_read < prev_read_file
+                    getline prev_write < prev_write_file
+
+                    diff_read    = (curr_read  - prev_read ) / bytes_per_unit
+                    diff_written = (curr_write - prev_write) / bytes_per_unit
+
+                    print curr_read  > prev_read_file
+                    print curr_write > prev_write_file
+
+                    io_stat = sprintf("%0.3f▲ %0.3f▼", diff_written, diff_read)
+                    if (interface ~ "^w") {
+                        label = label ":" wifi_conn
+                    }
+                } else {
+                    io_stat = "--"
+                }
+                number_of_interfaces_to_show = \
+                    split(\
+                        prefixes_of_interfaces_to_show,\
+                        array_of_prefixes_of_interfaces_to_show,\
+                        " +"\
+                    )
+                for (n = 1; n <= number_of_interfaces_to_show; n++) {
+                    prefix = array_of_prefixes_of_interfaces_to_show[n]
+                    if (interface ~ ("^" prefix)) {
+                        if (++count_printed > 1) {
+                            sep = "  "
+                        } else {
+                            sep = ""
+                        }
+                        printf("%s%s:%s", sep, label, io_stat)
+                    }
+                }
+            }
+        }'
+)
+
+energy=$(
+    upower -e \
+    | grep battery \
+    | xargs upower -i \
+    | awk '
+        /^ +percentage: +/ {percentage=$2}
+        /^ +state: +/      {state=$2}
+        END {
+            if (state == "discharging") {
+                direction_of_change = "<"
+            } else if (state == "charging") {
+                direction_of_change = ">"
+            } else {
+                direction_of_change = "="
+            };
+            printf("%s%s", direction_of_change, percentage)
+        }')
+
+datetime=$(date +'%a %b %d %H:%M:%S')
+#datetime=$(
+#    date +'%a %u %b %d %H:%M:%S' \
+#    | awk '
+#        {
+#            wday_name = $1
+#            wday_seq  = $2
+#            month     = $3
+#            mday      = $4
+#            time      = $5
+#
+#            week = ""
+#            for (i=1; i<=7; i++) {
+#                if (i == 6 || i == 4) {
+#                    sep = " "
+#                } else {
+#                    sep = ""
+#                }
+#
+#                if (i == wday_seq) {
+#                    #symbol = substr(wday_name, 1, 1)
+#                    symbol = "/"
+#                } else if (i < wday_seq){
+#                    symbol = "X"
+#                } else {
+#                    symbol = "_"
+#                }
+#                week = week sep symbol
+#            }
+#
+#            print "["week"]", month, mday, time;
+#        }
+#    '
+#)
+
+#volume_amixer=$(
+#    amixer get Master \
+#    | tail -1 \
+#    | awk '
+#        {
+#            level = $4;
+#            sub("^\\[", "", level);
+#            sub("\\]$", "", level);
+#            print level;
+#        }' \
+#    )
+
+#volume_amixer=$(
+#    amixer get Master \
+#    | tail -n 1 \
+#    | awk '{print $4}' \
+#    | tr -d '[]'
+#)
+
+volume_pactl=$(
+    pactl list sinks \
+    | awk '
+        /^\tMute:/ {
+            printf("%s,", $0);
+        }
+        /^\tVolume:/ {
+            for (i=2; i<=NF; i++) printf(" %s", $i);
+        }' \
+    | awk -v RS=',' '
+        /^[ \t]*Mute:/        {mute  = $2}
+        /^[ \t]*front-left:/  {left  = $4}
+        /^[ \t]*front-right:/ {right = $4}
+        END {
+            if (mute == "yes") {
+                printf("x")
+            } else {
+                printf("%s %s", left, right)
+            }
+        }
+        '
+)
+
+volume="($volume_pactl)"
+
+screen_brightness=$(
+    echo -n $((
+          $(cat $SCREEN_BRIGHTNESS_DEVICE_PATH/brightness)
+        / $(cat $SCREEN_BRIGHTNESS_DEVICE_PATH/max_brightness)
+        * 100
+    ))
+)
+
+#bluetooth_status=$(
+#    grep '^status:' /proc/acpi/ibm/bluetooth \
+#    | awk '
+#        $2 == "disabled" {printf "off"}
+#        $2 == "enabled"  {printf "on"}
+#        '
+#)
+
+bluetooth_power=$(
+    echo -e 'show \n quit' \
+    | bluetoothctl \
+    | awk '
+        /^Controller / {
+            controller = $2;
+            controllers[++ctrl_count] = controller;
+        }
+        /^\t[A-Z][A-Za-z]+:/ {
+            key = $1;
+            sub(":$", "", key);
+            val = $2;
+            for (i=3; i<=NF; i++) {
+                val = val " " $i};
+                data[controller, key] = val;
+        }
+        END {
+            # Using the 1st seen controller. Should we select specific instead?
+            power_status = data[controllers[1], "Powered"];
+            if (ctrl_count > 0) {
+                if (power_status == "no") {
+                    power_status = "off"
+                } else if (power_status == "yes") {
+                    power_status = "on"
+                } else {
+                    printf("Unexpected bluetooth power status: %s\n", power_status)\
+                        > "/dev/stderr";
+                    power_status = "ERROR"
+                }
+            } else {
+                power_status = "off"  # TODO: Perhaps use differentiated marker?
+            }
+            printf("%s", power_status);
+        }'
+)
+
+#touchpad_status=$(
+#    xinput list-props 12 \
+#    | awk '
+#        /^\tDevice Enabled \([0-9]+\):/ {
+#            status = $4;
+#            printf("%s", status);
+#        }'
+#)
+
+#color_off='\033[0m'
+#color_on_bg_gray='\033[m\033[40m'
+
+energy_direction=$(echo "$energy" | cut -b 1)
+energy_percentage=$(echo "$energy" | tr -d '<>=%')
+if [[ "$energy_direction" = '<' ]]
+then
+    if [[ $energy_percentage -le 5 ]]
+    then
+        DISPLAY=:0.0 notify-send \
+            -u critical \
+            "Energy CRITICALLY low: $energy" \
+            'CHARGE NOW!!! GO GO GO!!!'
+    elif [[ $energy_percentage -le 10 ]]
+    then
+        DISPLAY=:0.0 notify-send \
+            -u critical \
+            "Energy VERY low: $energy" \
+            'Plug it in ASAP.'
+    elif [[ $energy_percentage -le 15 ]]
+    then
+        DISPLAY=:0.0 notify-send \
+            -u critical \
+            "Energy low: $energy" \
+            'Get the charger.'
+    elif [[ $energy_percentage -le 50 ]]
+    then
+        if [[ ! -a "$STATUS_FILE__ENERGY_NOTIFIED_BELLOW_HALF" ]]
+        then
+            DISPLAY=:0.0 notify-send \
+                -u normal \
+                "Energy bellow half: $energy" \
+                'Where is the charger?'
+            touch "$STATUS_FILE__ENERGY_NOTIFIED_BELLOW_HALF"
+        fi
+    fi
+else
+    rm -f "$STATUS_FILE__ENERGY_NOTIFIED_BELLOW_HALF"
+fi
+
+weather=$(
+    awk \
+        'NR == 1 {printf("%s°F", $1)}' \
+        "$HOME/var/run/metar-${WEATHER_STATION_ID}-decoded-temp-fahrenheit"
+)
+
+#signal_last_msg_age=$(
+#    ls -lt --time-style=+%s $HOME/var/lib/signal/latest_message.json \
+#    | awk -v now_seconds=$(date +%s) \
+#    '{
+#        mtime_seconds = $6;
+#        seconds = now_seconds - mtime_seconds;
+#        minutes = seconds / 60;
+#        hours   = minutes / 60;
+#        days    = hours / 24;
+#        weeks   = days / 7;
+#        months  = days / 30;
+#        #fmt = "%.1f";
+#        fmt = "%d";
+#        printf(fmt " s\n", seconds);
+#        printf(fmt " m\n", minutes);
+#        printf(fmt " h\n", hours);
+#        printf(fmt " d\n", days);
+#        printf(fmt " w\n", weeks);
+#        printf(fmt " mo\n", months);
+#    }' \
+#    | awk '$1 >= 1' \
+#    | sort -n -k 1 \
+#    | head -1 \
+#    | tr -d ' '
+#)
+
+mpd_currentsong=$(
+    echo 'currentsong' \
+    | nc 127.0.0.1 6600 \
+    | awk -v max_chars=10 '
+        /^OK/ {
+            next
+        }
+
+        {
+            key = $1
+            val = $2
+            for (i=3; i<=NF; i++) {val = val " " $i}
+            data[key] = val
+        }
+
+        END {
+            name  = data["Name:"]
+            title = data["Title:"]
+            file  = data["file:"]
+
+            if (name) {
+                out = name
+            } else if (title) {
+                out = title
+            } else if (file) {
+                last = split(file, parts, "/")
+                out = parts[last]
+            } else {
+                out = ""
+            }
+
+            printf("%s", substr(out, 1, max_chars))
+        }
+        '
+)
+
+mpd_state=$(
+    echo 'status' \
+    | nc 127.0.0.1 6600 \
+    | awk \
+        -v current_song="$mpd_currentsong" \
+        '
+        {
+            status[$1] = $2
+        }
+
+        /^time: +[0-9]+:[0-9]+$/ {
+            split($2, time, ":")
+            seconds_current = time[1]
+            seconds_total   = time[2]
+
+            hours = int(seconds_current / 60 / 60);
+            secs_beyond_hours = seconds_current - (hours * 60 * 60);
+            mins = int(secs_beyond_hours / 60);
+            secs = secs_beyond_hours - (mins * 60);
+            if (hours > 0) {
+                current_time = sprintf("%d:%.2d:%.2d", hours, mins, secs)
+            } else {
+                current_time = sprintf("%.2d:%.2d", mins, secs)
+            }
+
+            if (seconds_total > 0) {
+                time_percentage = (seconds_current / seconds_total) * 100
+                current_percentage = sprintf("%d%%", time_percentage)
+            } else {
+                current_percentage = "~"
+            }
+        }
+
+        function print_known_state(symbol) {
+            printf(\
+                "%s %s %s %s",
+                symbol, current_time, current_percentage, current_song \
+            )
+        }
+
+        function print_unknown_state(symbol) {
+            printf("%s", symbol)
+        }
+
+        END {
+            state = status["state:"]
+
+            if (state == "play") {
+                print_known_state("▶")
+            } else if (state == "pause") {
+                print_known_state("❚❚")
+            } else if (state == "stop") {
+                print_known_state("⬛")
+            } else {
+                print_unknown_state("--")
+            }
+        }
+        '
+)
+
+#graphics_card=$(
+    #nvidia-smi \
+        #--format=csv,noheader,nounits \
+        #--query-gpu=memory.total,memory.used,temperature.gpu \
+    #| awk -F ',' '
+        #{
+            #mem_total = $1;
+            #mem_used  = $2;
+            #temp      = $3;
+            #mem_used_percent = (100 * mem_used) / mem_total;
+            #printf("[%d%% %dC]", mem_used_percent, temp);
+        #}
+        #'
+#)
+
+echo \
+"\
+ E$energy\
+ \
+ M$memory\
+ \
+ C=[$load ${temp}°C ${fan}rpm]\
+ \
+ D$disk\
+ \
+ N:[$network]\
+ \
+ B:$bluetooth_power\
+ \
+ *$screen_brightness%\
+ \
+ $volume\
+ \
+ [$mpd_state]\
+ \
+ $weather\
+ \
+ $datetime \
+"
diff --git a/v1/bin/khatus_update_network b/v1/bin/khatus_update_network
new file mode 100755 (executable)
index 0000000..f3b562f
--- /dev/null
@@ -0,0 +1,37 @@
+#! /bin/bash
+
+set -e
+
+#TERM=xterm-256color  # To keep unicode charcters from BARS
+
+STATUS_DIR=$HOME/var/run/status
+STATUS_FILE_WIFI=$STATUS_DIR/wifi
+STATUS_FILE_ETH=$STATUS_DIR/eth
+
+mkdir -p $STATUS_DIR
+
+# nmcli d \
+# | awk \
+#     -v file_wifi="$STATUS_FILE_WIFI" \
+#     -v file_eth="$STATUS_FILE_ETH" \
+#     '
+#     $2 == "wifi"     {wifi = $4}
+#     $2 == "ethernet" {eth=$4}
+#     END {
+#         print(wifi) > file_wifi;
+#         print(eth)  > file_eth;
+#     }
+#     '
+
+nmcli \
+    -f ACTIVE,SSID,SIGNAL \
+    -t \
+    d wifi \
+| awk \
+    -F ':' \
+    -v file_wifi="$STATUS_FILE_WIFI" \
+    '
+    BEGIN       {wifi_status = "--"}
+    $1 == "yes" {wifi_status =  $2 ":" $3 "%"}
+    END         {print wifi_status > file_wifi}
+    '
diff --git a/v1/bin/khatus_update_weather b/v1/bin/khatus_update_weather
new file mode 100755 (executable)
index 0000000..665ae07
--- /dev/null
@@ -0,0 +1,35 @@
+#! /bin/bash
+
+set -e
+
+STATION_ID="$1"  # ICAO designator. e.g. KJFK, KBOS
+
+FILE_METAR_DECODED="$HOME/var/run/metar-${STATION_ID}-decoded"
+FILE_TEMP_FAHRENHEIT="${FILE_METAR_DECODED}-temp-fahrenheit"
+FILE_TEMP_CELSIUS="${FILE_METAR_DECODED}-temp-celsius"
+
+(metar -d "$STATION_ID" 2>&1) > $FILE_METAR_DECODED  # TODO: Better error handling
+
+awk \
+    -v file_fahrenheit="$FILE_TEMP_FAHRENHEIT" \
+    -v file_celsius="$FILE_TEMP_CELSIUS" \
+    '
+    /METAR pattern not found in NOAA data/ {
+        failures++
+    }
+
+    /^Temperature/ {
+        celsius = $3;
+        fahrenheit = (celsius * (9 / 5)) + 32;
+    }
+
+    END {
+        if (failures > 0) {
+            print "--" > file_fahrenheit
+            print "--" > file_celsius
+        } else {
+            print fahrenheit > file_fahrenheit
+            print celsius    > file_celsius
+        }
+    }' \
+    $FILE_METAR_DECODED
diff --git a/v1/install b/v1/install
new file mode 100755 (executable)
index 0000000..44fa3fe
--- /dev/null
@@ -0,0 +1,15 @@
+#! /bin/sh
+
+PREFIX="$HOME/bin"
+
+if [ $1 ]
+then
+    PREFIX=$1
+fi
+
+cd bin
+
+for filename in *
+do
+    ln -s "`pwd`/$filename" "$PREFIX/$filename"
+done
This page took 0.035683 seconds and 4 git commands to generate.