dot rc

Sign in or create your account | Project List | Help

dot rc Git Source Tree

Root/rc/bash_functions

Source at commit 2bfddbfae911e1df474fa06858ce63b611716441 created 1 year 10 months ago.
By Luciano Rocha, perldbg: also load modules from command line
1# vim: et sw=4 ts=4 filetype=sh
2# .bashrc with functions for interactive shells
3
4## doc: err message: send message to stderr
5err()
6{
7    local f="${FUNCNAME[1]}"
8    echo "${f:+$f: }$*" 1>&2
9}
10
11## doc: remove a repetition of a character from the beginning of a string
12ltrim()
13{
14    local c s r
15    c="$1"
16    shift
17    s="$*"
18    r="${s#$c}"
19    while [ "$r" != "$s" ]; do
20        s="$r"
21        r="${s#$c}"
22    done
23    echo "$r"
24}
25
26## doc: remove a repetition of a character from the end of a string
27rtrim()
28{
29    local c s r
30    c="$1"
31    shift
32    s="$*"
33    r="${s%$c}"
34    while [ "$r" != "$s" ]; do
35        s="$r"
36        r="${s%$c}"
37    done
38    echo "$r"
39}
40
41## doc: remove a repetition of a character from the beginning and end of a string
42trim()
43{
44    local c="$1"
45    shift
46    ltrim "$c" $(rtrim "$c" $*)
47}
48
49## doc: start screen
50s()
51{
52    if [ -z "$STY" ]; then
53        export SCREENTERM=$TERM
54        screen -RR -D
55    else
56        err already running under screen
57    fi
58}
59
60## doc: simple http cat
61wcat()
62{
63    local url host port path file header
64    while [ "$1" ]; do
65        url="${1#http://}"
66        shift
67
68        host="${url%%/*}"
69        port="${host#*:}"
70        [ "$port" = "$host" ] && port=80
71        host="${host%%:*}"
72        path="${url#*/}"
73        if [ "$path" = "$url" ]; then
74            path="/"
75        else
76            path="/$path"
77        fi
78        file="${path##*/}"
79        [ -z "$file" ] && file="index.html"
80        echo -n "http://$host:$port$path -> $file"
81        (
82            echo -en 'GET '$path' HTTP/1.0\r\n'
83            echo -en 'Host: '$host:$port'\r\n\r\n'
84            while read header ; do
85                [ "${#header}" -lt 3 ] && break
86            done
87            cat > "$file"
88        ) <> /dev/tcp/$host/$port 1>&0
89        echo
90    done
91}
92
93## equals passwordcomposer
94## http://www.xs4all.nl/~jlpoutre/BoT/Javascript/PasswordComposer/
95## doc: passwordcomposer function
96pass()
97{
98    local host pass
99    host="$1"
100    pass="$2"
101
102    if [ -z "$host" ]; then
103        echo -n "Enter domain name: "
104        read host
105    fi
106    (
107    if [ -z "$pass" ]; then
108        trap "stty echo" EXIT
109        echo -n "Enter master password (won't echo): "
110        stty -echo
111        read pass
112        stty echo
113        echo
114    fi
115    echo -n "$pass:$host" | (md5sum || md5 || openssl md5 -hex) 2>/dev/null \
116        | cut -b 1-8
117    )
118}
119
120## extract archives
121## doc: extract archives
122extract()
123{
124    local arg t dir tmp abs dest
125    for arg; do
126        if ! [ -e "$arg" ]; then
127            err "$arg: doesn't exist, skipped"
128            continue
129        fi
130
131        if [ -z "${arg%%/*}" ]; then
132            abs="$arg"
133        else
134            abs="$PWD/$arg"
135        fi
136
137        if [ "$(uname -s)" = Darwin ]; then
138            t=$(file -I "$abs")
139        else
140            t=$(file -i "$abs")
141        fi
142
143        # remove ; charset=..
144        t="${t%%;*}"
145
146        if [ -z "$t" ] || [ "$t" = "application/octet-stream" ]; then
147            t="${arg##*.}"
148        fi
149
150        if [ -z "$t" ]; then
151            err "$arg: couldn't detect type"
152            continue
153        fi
154
155        if [ -z "${t##*text/*}" ]; then
156            err "$arg: not an archive"
157            continue
158        fi
159
160        dest="${arg##*/}"
161        dest="${dest%.*}"
162
163        if [ -z "$dest" ]; then
164            err "$arg: no useful name extracted"
165            continue
166        fi
167
168        dir=".__${dest}__";
169
170        if [ -e "$dir" ]; then
171            err "$arg: temporary directory ($dir) already exists, remove it"
172            continue
173        fi
174
175        mkdir -p "$dir"
176
177        case "$t" in
178            *rpm)
179            tmp=$(rpm -qp --nosignature "$abs" --qf '%{name}-%{version}-%{release}.%{arch}')
180            mkdir -p "$dir/$tmp"
181            rpm2cpio "$abs" | (cd "$dir/$tmp" && cpio -idu --no-absolute-filenames --quiet)
182            ;;
183            *gzip)
184            if [ -z "${arg##*.tgz}" ] || [ -z "${arg##*tar*}" ]; then
185                tar -xzpf "$abs" -C "$dir"
186            else
187                zcat < "$abs" > "$dir/$dest"
188            fi
189            ;;
190            *bzip2)
191            if [ -z "${arg##*.tbz*}" ] || [ -z "${arg##*tar*}" ]; then
192                tar -xjpf "$abs" -C "$dir"
193            else
194                bzcat < "$abs" > "$dir/$dest"
195            fi
196            ;;
197            *zip)
198            unzip -q -d "$dir" "$abs"
199            ;;
200            *rar)
201            (cd "$dir" && unrar -inul x "$abs")
202            ;;
203            *iso*)
204            tmp=""
205            if isoinfo -f -R -i "$abs" &> /dev/null; then
206                tmp="-R"
207            elif isoinfo -f -J -i "$abs" &> /dev/null; then
208                tmp="-J"
209            fi
210            isoinfo $tmp -f -i "$abs" | while read; do
211                REPLY="${REPLY%;[0-9]*}"
212                REPLY="${REPLY%.}"
213                t="$dir/${REPLY%/*}"
214                if [ -f "$t" ]; then
215                    rm -f "$t"
216                fi
217                mkdir -p "$t"
218                isoinfo $tmp -x "$REPLY" -i "$abs" > "$dir/$REPLY"
219            done
220            ;;
221            *)
222            err "$arg: couldn't detect type"
223            rmdir "$dir"
224            continue
225            ;;
226        esac
227
228        tmp=("$dir/"*)
229        if ! [ -e "$tmp" ]; then
230            err "$arg: nothing extracted"
231            rmdir "$dir"
232        elif [ "${#tmp[*]}" -gt 1 ]; then
233            tmp="$dest"
234            t=1
235            while [ -e "$tmp" ]; do
236                tmp="$dest.$((t++))"
237            done
238            mv -f "$dir" "$tmp"
239            echo "$arg: extracted to $tmp"
240        else
241            dest="${tmp##*/}"
242            t=1
243            tmp="$dest"
244            while [ -e "$tmp" ]; do
245                tmp="$dest.$((t++))"
246            done
247            mv -f "$dir/"* "$tmp"
248            echo "$arg: extracted to $tmp"
249            rmdir "$dir"
250        fi
251    done
252}
253
254## doc: show KB size in number of CDs or DVDs
255size_cds()
256{
257    local size="$1" dvds cds
258
259    ((cds=size/683593))
260    if [ $((size%683593)) -gt 0 ]; then
261        ((cds++))
262    fi
263
264    ((dvds=size/4589843))
265    if [ $((size%4589843)) -gt 0 ]; then
266        ((dvds++))
267    fi
268
269    echo "$cds CDs, $dvds DVDs"
270}
271
272## doc: compute expected iso size
273size_iso()
274{
275    local calc size arg tmp do_total
276    calc="mkisofs -J -joliet-long -r -pad -V LABEL -print-size -q"
277    if [ $# -ge 1 ]; then
278        if [ "$1" = "-c" ]; then
279            do_total=1
280            shift
281        fi
282        for arg; do
283            tmp=$(($($calc "$arg")*2))
284            echo "$arg: ${tmp}KB $((tmp/1024))MB: $(size_cds $tmp)"
285            ((size += tmp))
286        done
287        if [ -n "$do_total" ]; then
288            echo "total: ${size}KB $((size/1024))MB: $(size_cds $size)"
289        fi
290    else
291        tmp=$(($($calc .)*2))
292        echo "${tmp}KB $((tmp/1024))MB: $(size_cds $tmp)"
293    fi
294}
295
296## doc: compute expected playlist size, for DVDs
297size_playlist()
298{
299     perl -n -e '
300        if (/file:/) {
301            chomp;
302            s/.*file:..//;
303            s/%(..)/chr(hex($1))/ge;
304            my $size = (stat($_))[7];
305            $total += int($size / 2048);
306            $total++ if $size % 2048;
307        }
308        END {
309            $size = $total * 2048;
310            $size_gb = $size / 1024.0 / 1024.0 /1024.0;
311            $dvd = $total*100.0/2294921.0;
312            $free = ((100.0 - $dvd) / 100.0) * 2294921.0 / 512.0;
313            $free_t = $free * 1024.0 * 1024.0 / 16000.0;
314            $free_h = int($free_t / 3600.0);
315            $free_m = int(($free_t - $free_h * 3600.0) / 60.0);
316            $time = $free_h ? $free_h . "h" : "";
317            $time .= $free_m ? $free_m . "m" : "";
318            printf "sectors: \%s\n".
319                "size: \%.0f (\%.2f GB)\n".
320                "dvd: \%.2f\%\%\n".
321                "free: %.2f MB ~ %s\n",
322                $total, $size, $size_gb, $dvd, $free, $time;
323        }
324        ' "$@"
325}
326
327
328## w/ colordiff installed
329if type -p cdiff &> /dev/null; then
330    _use_cdiff()
331    {
332        if [ -t 1 ]; then
333            "$@" | cdiff
334        else
335            "$@"
336        fi
337    }
338else
339    _use_cdiff()
340    {
341        if [ -t 1 ]; then
342            "$@" | $PAGER
343        else
344            "$@"
345        fi
346    }
347fi
348
349## doc: make svn more user-friendly
350svn() { _dvcs svn "$@"; }
351
352## doc: make hg more user-friendly
353hg() { _dvcs hg "$@"; }
354
355## doc: make cvs more user-friendly
356cvs() { _dvcs cvs "$@"; }
357
358## make hg/svn/alikes more user-friendly
359_dvcs()
360{
361    local cmd="$(type -P $1)"
362    shift
363
364    if [ "$1" = "diff" ]; then
365        _use_cdiff "$cmd" "$@"
366    elif [ -t 1 ] && [ "$1" = "help" -o "$1" = "blame" -o "$1" = "log" ]; then
367        "$cmd" "$@" | $PAGER
368    else
369        "$cmd" "$@"
370    fi
371}
372
373## doc: colorize output of diff
374diff()
375{
376    _use_cdiff "$(type -P diff)" -u "$@"
377}
378
379## doc: crypt(3)
380crypt()
381{
382    local pass salt crypt
383    pass="$1"
384    salt="$2"
385
386    [ -z "$pass" ] && return
387    if [ -z "$salt" ]; then
388        salt="\$1\$$(perl -e 'print map { $_ < 10 ? chr $_ + 48 : $_ < 36 ? chr $_ + 55 : chr $_ + 61 } map { int rand 62 } 1..8')\$"
389    fi
390    crypt=$(perl -e "print crypt('$pass', '$salt')")
391    echo crypt: $crypt
392    echo base64: $(perl -MMIME::Base64 -e "print encode_base64('{crypt}'.'$crypt')")
393}
394
395## run vim
396svim()
397{
398    _vim vim "$@"
399}
400
401## run gvim, open multiple windows for multiple files
402mvim()
403{
404    local a args opt nonopt fg
405    declare -a args
406    declare -a opt
407    declare -a nonopt
408
409    fg=
410
411    for a; do
412        if [ -z "${a##-*}" ]; then
413            [ "$a" = "-f" ] && fg=1
414            opt=("${opt[@]}" "$a")
415        else
416            nonopt=("${nonopt[@]}" "$a")
417        fi
418    done
419    if [ -n "$fg" -o "${#nonopt[@]}" -gt 7 ]; then
420        _vim gvim "${opt[@]}" "${nonopt[@]}"
421        return
422    fi
423
424    if [ "${#nonopt[@]}" -eq 0 ]; then
425        gvim "${opt[@]}"
426        return
427    fi
428
429    for a in "${nonopt[@]}"; do
430        if [ -z "${a##+*}" ]; then
431            args=("${args[@]}" "$a")
432        elif [ ${#args[*]} -gt 0 ]; then
433            _vim gvim "${opt[@]}" "${args[@]}"
434            args=("$a")
435        else
436            args=("$a")
437        fi
438    done
439    if [ ${#args[*]} -gt 0 ]; then
440        _vim gvim "${opt[@]}" "${args[@]}"
441    fi
442}
443
444## smart vim: tranform file:line -> +line, file:func() -> file +/func/
445_vim()
446{
447    local vi args a n t aa
448    declare -a args
449
450    vi="$1"
451    shift
452    for a; do
453        if [ -e "$a" ] || [ -z "${a##*[0-9]:[0-9]}" ]; then
454            ## file exists, or probably an interface alias
455            ## use as is
456            args=("${args[@]}" "$a")
457            continue
458        fi
459        ## remove trailing ':', output by grep -n, for instance
460        aa="${a/%:}"
461        if [ "$aa" != "${aa%:[0-9]*}" ]; then
462            ## with line information
463            n="${aa##*:}"
464            aa="${aa%:*}"
465            ## must exist
466            if [ -e "$aa" ]; then
467                args=("${args[@]}" "$aa" "+$n")
468            else
469                args=("${args[@]}" "$a")
470            fi
471        elif [ "$aa" != "${aa%::*}" ]; then
472            ## with function
473            aa="${aa/%()}"
474            n="${aa##*::}"
475            aa="${aa%::*}"
476            aa="${aa//\\/\\\\}"
477            ## must exist
478            if [ -e "$aa" ]; then
479                args=("${args[@]}" "$aa" \
480                    '+/\v((sub|function|def)\s+<\V'"$n"'\v>)|(<'"$n"'>\s*\()')
481            else
482                args=("${args[@]}" "$a")
483            fi
484        else
485            ## use as is
486            args=("${args[@]}" "$a")
487        fi
488    done
489    command $vi "${args[@]}"
490}
491
492## doc: list directories in arguments
493ldir()
494{
495    local arg
496    if [ -z "${1##-*}" ]; then
497        arg="$1"
498        shift
499    fi
500    find "$@" -maxdepth 1 -type d -print0 | xargs -0r ls --color=auto -d $arg
501}
502
503## doc: list symbolic links in arguments
504lln()
505{
506    local arg
507    if [ -z "${1##-*}" ]; then
508        arg="$1"
509        shift
510    fi
511    find "$@" -maxdepth 1 -type l -print0 | xargs -0r ls --color=auto -dF $arg
512}
513
514## doc: test a perl program
515perl_test()
516{
517    (
518        ulimit -c 0
519        perl -Ilib -I. "$@"
520    ) 2>&1 | $PAGER
521}
522
523## doc: run the perl debugger with usual modules
524perldbg()
525{
526    (
527        ulimit -c 0
528        mod=(YAML::XS=Load,Dump,LoadFile,DumpFile
529            Data::Dumper
530            MIME::Base64)
531
532        aval=()
533        for m in "${mod[@]}"; do
534            if perl "-M$m" -e 1 &> /dev/null; then
535                aval[ ${#aval[@]} ]="$m"
536            fi
537        done
538
539        e=()
540        for m; do
541            if [ -z "${m##*::*}" ]; then
542                if perl "-M$m" -e 1 &> /dev/null; then
543                    aval[ ${#aval[@]} ]="$m"
544                else
545                    echo "skipping $m, unable to load it" >&2
546                fi
547            elif [ -e "$m" ]; then
548                e[ ${#e[@]} ]="require '$m';"
549            else
550                e[ ${#e[@]} ]="$m;"
551            fi
552        done
553
554        echo "will import modules: ${aval[*]}" >&2
555        echo "will execute: ${e[*]} 1" >&2
556        perl -Ilib -I. -d "${aval[@]/#/-M}" "${e[@]/#/-e}" -e1
557    )
558}
559
560## doc: create a bare git clone
561git-bare()
562{
563    ( set +m; _git-bare-bg "$@" )
564}
565
566_git-bare-bg()
567{
568    local url tmpd name
569
570    tmpd=`mktemp -d` || exit 1
571    trap "rm -fr $tmpd" EXIT
572
573    for url; do
574        ## remove /.git
575        name=$(rtrim / "$url")
576        name="${name%.git}"
577        name=$(rtrim / "$name")
578
579        ## remove url, add .git
580        name="${name##*/}.git"
581
582        if [ "$name" = ".git" ]; then
583            echo "coudln't get name for $url"
584            continue
585        fi
586
587        if [ -d "$name" ]; then
588            echo "skipping $name, already exists"
589            continue
590        fi
591        (
592            if { git clone --bare "$url" "$name" &&
593                cd "$name" &&
594                git remote add -f --mirror origin "$url" ||
595                {
596                    git config remote.origin.url "$url" &&
597                    git config remote.origin.fetch "+refs/heads/*:refs/heads/*"
598                }
599            } &> $tmpd/$$; then
600                echo "finished $name"
601            else
602                echo "failed to create $name:"
603                tail -n 3 $tmpd/$$
604            fi
605        ) &
606    done
607    wait
608}
609
610## doc: remove a line from a file: rmline <file> <line> or <file:line>
611rmline()
612{
613    local file line
614
615    file="$1"
616    line="$2"
617
618    if [ -z "$file" ]; then
619        err "missing file to remove"
620        return 1
621    fi
622
623    if [ -z "$line" ]; then
624        line="${file##*:}"
625        file="${file%:*}"
626    fi
627
628    if ! [ -e "$file" ]; then
629        err "file to remove doesn't exist"
630        return 1
631    fi
632
633    if [ -z "$line" ]; then
634        err "missing line to remove"
635        return 1
636    fi
637
638    ed -s "$file" <<-EOF
639        ${line}d
640        wq
641EOF
642}
643
644## doc: show local IP addresses
645ips()
646{
647    (
648        PATH=$PATH:/usr/sbin:/sbin
649        if _exists ip; then
650            ip addr show to 0/0
651        else
652            ifconfig | awk '/^[^ \t]/{i=$1} /inet/{ print i $0}'
653        fi
654    )
655}
656
657## doc: list interfaces belonging to a bridge
658brif()
659{
660    local br="$1"
661    shift
662
663    brctl show | awk -v br=$br '
664        BEGIN { inbr=0 }
665        /^[^ \t]/ { inbr=0 }
666        $1 == br {
667            if ($4) { print $4 }
668            inbr=1
669        }
670        /^[ \t]/ && inbr==1 { print $1 }
671    '
672}
673
674## doc: list content differences between two directories
675dirdiff()
676{
677    local src="$1" dst
678    dst="${2:-.}"
679
680    if [ -z "$src" ]; then
681        err "missing original directory"
682        return 1
683    fi
684
685    if ! [ -d "$src" ]; then
686        err "$src: not a directory"
687        return 1
688    fi
689    if ! [ -d "$dst" ]; then
690        err "$dst: not a directory"
691        return 1
692    fi
693
694    diff -u <(cd "$src" && find . | LC_ALL=C sort | sed -e 's/^..//') \
695        <(cd "$dst" && find . | LC_ALL=C sort | sed -e 's/^..//')
696}
697
698## doc: execute command with path to a binary; path added to the end or where '%' is
699bin()
700{
701    local p a cmd spec
702
703    p=$(type -P "$1" 2>/dev/null)
704    if [ -z "$p" ]; then
705        err "couldn't find $1"
706        return 1
707    fi
708    shift
709
710    if [ $# -eq 0 ]; then
711        echo $p
712        return 0
713    fi
714
715    declare -a cmd
716    spec=
717    for a; do
718        if [ "$a" = "%" ]; then
719            cmd[ ${#cmd[@]} ]="$p"
720            spec=1
721        else
722            cmd[ ${#cmd[@]} ]="$a"
723        fi
724    done
725    [ -z "$spec" ] && cmd[ ${#cmd[@]} ]="$p"
726    eval "${cmd[@]}"
727}
728
729## doc: show nfo
730nfo()
731{
732    local f="$1" a
733
734    if [ -d "$f" ]; then
735        declare -a a
736        a=("$f"/*.[nN][fF][oO])
737        f="$a"
738    fi
739
740    if ! [ -f "$f" ]; then
741        err "couldn't find nfo in $f"
742        return 1
743    fi
744
745    iconv -f cp437 "$f" | tr -d '\r' | sed -e 's/^ *$//' |
746        LESS="${LESS:--}rsS" $PAGER
747}
748
749

Archive Download this file

Branches:
master