dot rc

Sign in or create your account | Project List | Help

dot rc Git Source Tree

Root/rc/bash_functions

Source at commit d4d937da5858f9768eacd150503803db75711dc4 created 2 years 10 months ago.
By Luciano M. F. Rocha, ignore mime-type options when checking file type for extraction
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        t=$(file -i "$abs")
138        # remove ; charset=..
139        t="${t%%;*}"
140
141        if [ -z "$t" ] || [ "$t" = "application/octet-stream" ]; then
142            t="${arg##*.}"
143        fi
144
145        if [ -z "$t" ]; then
146            err "$arg: couldn't detect type"
147            continue
148        fi
149
150        if [ -z "${t##*text/*}" ]; then
151            err "$arg: not an archive"
152            continue
153        fi
154
155        dest="${arg##*/}"
156        dest="${dest%.*}"
157
158        if [ -z "$dest" ]; then
159            err "$arg: no useful name extracted"
160            continue
161        fi
162
163        dir=".__${dest}__";
164
165        if [ -e "$dir" ]; then
166            err "$arg: temporary directory ($dir) already exists, remove it"
167            continue
168        fi
169
170        mkdir -p "$dir"
171
172        case "$t" in
173            *rpm)
174            tmp=$(rpm -qp --nosignature "$abs" --qf '%{name}-%{version}-%{release}.%{arch}')
175            mkdir -p "$dir/$tmp"
176            rpm2cpio "$abs" | (cd "$dir/$tmp" && cpio -idu --no-absolute-filenames --quiet)
177            ;;
178            *gzip)
179            if [ -z "${arg##*.tgz}" ] || [ -z "${arg##*tar*}" ]; then
180                tar -xzpsSf "$abs" -C "$dir"
181            else
182                zcat < "$abs" > "$dir/$dest"
183            fi
184            ;;
185            *bzip2)
186            if [ -z "${arg##*.tbz*}" ] || [ -z "${arg##*tar*}" ]; then
187                tar -xjpsSf "$abs" -C "$dir"
188            else
189                bzcat < "$abs" > "$dir/$dest"
190            fi
191            ;;
192            *zip)
193            unzip -q -d "$dir" "$abs"
194            ;;
195            *rar)
196            (cd "$dir" && unrar -inul x "$abs")
197            ;;
198            *iso*)
199            tmp=""
200            if isoinfo -f -R -i "$abs" &> /dev/null; then
201                tmp="-R"
202            elif isoinfo -f -J -i "$abs" &> /dev/null; then
203                tmp="-J"
204            fi
205            isoinfo $tmp -f -i "$abs" | while read; do
206                REPLY="${REPLY%;[0-9]*}"
207                REPLY="${REPLY%.}"
208                t="$dir/${REPLY%/*}"
209                if [ -f "$t" ]; then
210                    rm -f "$t"
211                fi
212                mkdir -p "$t"
213                isoinfo $tmp -x "$REPLY" -i "$abs" > "$dir/$REPLY"
214            done
215            ;;
216            *)
217            err "$arg: couldn't detect type"
218            rmdir "$dir"
219            continue
220            ;;
221        esac
222
223        tmp=("$dir/"*)
224        if ! [ -e "$tmp" ]; then
225            err "$arg: nothing extracted"
226            rmdir "$dir"
227        elif [ "${#tmp[*]}" -gt 1 ]; then
228            tmp="$dest"
229            t=1
230            while [ -e "$tmp" ]; do
231                tmp="$dest.$((t++))"
232            done
233            mv -f "$dir" "$tmp"
234            echo "$arg: extracted to $tmp"
235        else
236            dest="${tmp##*/}"
237            t=1
238            tmp="$dest"
239            while [ -e "$tmp" ]; do
240                tmp="$dest.$((t++))"
241            done
242            mv -f "$dir/"* "$tmp"
243            echo "$arg: extracted to $tmp"
244            rmdir "$dir"
245        fi
246    done
247}
248
249## doc: show KB size in number of CDs or DVDs
250size_cds()
251{
252    local size="$1" dvds cds
253
254    ((cds=size/683593))
255    if [ $((size%683593)) -gt 0 ]; then
256        ((cds++))
257    fi
258
259    ((dvds=size/4589843))
260    if [ $((size%4589843)) -gt 0 ]; then
261        ((dvds++))
262    fi
263
264    echo "$cds CDs, $dvds DVDs"
265}
266
267## doc: compute expected iso size
268size_iso()
269{
270    local calc size arg tmp do_total
271    calc="mkisofs -J -joliet-long -r -pad -V LABEL -print-size -q"
272    if [ $# -ge 1 ]; then
273        if [ "$1" = "-c" ]; then
274            do_total=1
275            shift
276        fi
277        for arg; do
278            tmp=$(($($calc "$arg")*2))
279            echo "$arg: ${tmp}KB $((tmp/1024))MB: $(size_cds $tmp)"
280            ((size += tmp))
281        done
282        if [ -n "$do_total" ]; then
283            echo "total: ${size}KB $((size/1024))MB: $(size_cds $size)"
284        fi
285    else
286        tmp=$(($($calc .)*2))
287        echo "${tmp}KB $((tmp/1024))MB: $(size_cds $tmp)"
288    fi
289}
290
291## doc: compute expected playlist size, for DVDs
292size_playlist()
293{
294     perl -n -e '
295        if (/file:/) {
296            chomp;
297            s/.*file:..//;
298            s/%(..)/chr(hex($1))/ge;
299            my $size = (stat($_))[7];
300            $total += int($size / 2048);
301            $total++ if $size % 2048;
302        }
303        END {
304            $size = $total * 2048;
305            $size_gb = $size / 1024.0 / 1024.0 /1024.0;
306            $dvd = $total*100.0/2294921.0;
307            $free = ((100.0 - $dvd) / 100.0) * 2294921.0 / 512.0;
308            $free_t = $free * 1024.0 * 1024.0 / 16000.0;
309            $free_h = int($free_t / 3600.0);
310            $free_m = int(($free_t - $free_h * 3600.0) / 60.0);
311            $time = $free_h ? $free_h . "h" : "";
312            $time .= $free_m ? $free_m . "m" : "";
313            printf "sectors: \%s\n".
314                "size: \%.0f (\%.2f GB)\n".
315                "dvd: \%.2f\%\%\n".
316                "free: %.2f MB ~ %s\n",
317                $total, $size, $size_gb, $dvd, $free, $time;
318        }
319        ' "$@"
320}
321
322
323## w/ colordiff installed
324if type -p cdiff &> /dev/null; then
325    _use_cdiff()
326    {
327        if [ -t 1 ]; then
328            "$@" | cdiff
329        else
330            "$@"
331        fi
332    }
333else
334    _use_cdiff()
335    {
336        if [ -t 1 ]; then
337            "$@" | $PAGER
338        else
339            "$@"
340        fi
341    }
342fi
343
344## doc: make svn more user-friendly
345svn() { _dvcs svn "$@"; }
346
347## doc: make hg more user-friendly
348hg() { _dvcs hg "$@"; }
349
350## doc: make cvs more user-friendly
351cvs() { _dvcs cvs "$@"; }
352
353## make hg/svn/alikes more user-friendly
354_dvcs()
355{
356    local cmd="$(type -P $1)"
357    shift
358
359    if [ "$1" = "diff" ]; then
360        _use_cdiff "$cmd" "$@"
361    elif [ -t 1 ] && [ "$1" = "help" -o "$1" = "blame" -o "$1" = "log" ]; then
362        "$cmd" "$@" | $PAGER
363    else
364        "$cmd" "$@"
365    fi
366}
367
368## doc: colorize output of diff
369diff()
370{
371    _use_cdiff "$(type -P diff)" -u "$@"
372}
373
374## doc: crypt(3)
375crypt()
376{
377    local pass salt crypt
378    pass="$1"
379    salt="$2"
380
381    [ -z "$pass" ] && return
382    if [ -z "$salt" ]; then
383        salt="\$1\$$(perl -e 'print map { $_ < 10 ? chr $_ + 48 : $_ < 36 ? chr $_ + 55 : chr $_ + 61 } map { int rand 62 } 1..8')\$"
384    fi
385    crypt=$(perl -e "print crypt('$pass', '$salt')")
386    echo crypt: $crypt
387    echo base64: $(perl -MMIME::Base64 -e "print encode_base64('{crypt}'.'$crypt')")
388}
389
390## run vim
391svim()
392{
393    _vim vim "$@"
394}
395
396## run gvim, open multiple windows for multiple files
397mvim()
398{
399    local a args opt nonopt fg
400    declare -a args
401    declare -a opt
402    declare -a nonopt
403
404    fg=
405
406    for a; do
407        if [ -z "${a##-*}" ]; then
408            [ "$a" = "-f" ] && fg=1
409            opt=("${opt[@]}" "$a")
410        else
411            nonopt=("${nonopt[@]}" "$a")
412        fi
413    done
414    if [ -n "$fg" -o "${#nonopt[@]}" -gt 7 ]; then
415        _vim gvim "${opt[@]}" "${nonopt[@]}"
416        return
417    fi
418
419    if [ "${#nonopt[@]}" -eq 0 ]; then
420        gvim "${opt[@]}"
421        return
422    fi
423
424    for a in "${nonopt[@]}"; do
425        if [ -z "${a##+*}" ]; then
426            args=("${args[@]}" "$a")
427        elif [ ${#args[*]} -gt 0 ]; then
428            _vim gvim "${opt[@]}" "${args[@]}"
429            args=("$a")
430        else
431            args=("$a")
432        fi
433    done
434    if [ ${#args[*]} -gt 0 ]; then
435        _vim gvim "${opt[@]}" "${args[@]}"
436    fi
437}
438
439## smart vim: tranform file:line -> +line, file:func() -> file +/func/
440_vim()
441{
442    local vi args a n t aa
443    declare -a args
444
445    vi="$1"
446    shift
447    for a; do
448        if [ -e "$a" ] || [ -z "${a##*[0-9]:[0-9]}" ]; then
449            ## file exists, or probably an interface alias
450            ## use as is
451            args=("${args[@]}" "$a")
452            continue
453        fi
454        ## remove trailing ':', output by grep -n, for instance
455        aa="${a/%:}"
456        if [ "$aa" != "${aa%:[0-9]*}" ]; then
457            ## with line information
458            n="${aa##*:}"
459            aa="${aa%:*}"
460            ## must exist
461            if [ -e "$aa" ]; then
462                args=("${args[@]}" "$aa" "+$n")
463            else
464                args=("${args[@]}" "$a")
465            fi
466        elif [ "$aa" != "${aa%::*}" ]; then
467            ## with function
468            aa="${aa/%()}"
469            n="${aa##*::}"
470            aa="${aa%::*}"
471            aa="${aa//\\/\\\\}"
472            ## must exist
473            if [ -e "$aa" ]; then
474                args=("${args[@]}" "$aa" \
475                    '+/\v((sub|function|def)\s+<\V'"$n"'\v>)|(<'"$n"'>\s*\()')
476            else
477                args=("${args[@]}" "$a")
478            fi
479        else
480            ## use as is
481            args=("${args[@]}" "$a")
482        fi
483    done
484    command $vi "${args[@]}"
485}
486
487## doc: list directories in arguments
488ldir()
489{
490    local arg
491    if [ -z "${1##-*}" ]; then
492        arg="$1"
493        shift
494    fi
495    find "$@" -maxdepth 1 -type d -print0 | xargs -0r ls --color=auto -d $arg
496}
497
498## doc: list symbolic links in arguments
499lln()
500{
501    local arg
502    if [ -z "${1##-*}" ]; then
503        arg="$1"
504        shift
505    fi
506    find "$@" -maxdepth 1 -type l -print0 | xargs -0r ls --color=auto -dF $arg
507}
508
509## doc: test a perl program
510perl_test()
511{
512    (
513        ulimit -c 0
514        perl -Ilib -I. "$@"
515    ) 2>&1 | $PAGER
516}
517
518## doc: run the perl debugger with usual modules
519perldbg()
520{
521    (
522        ulimit -c 0
523        perl -Ilib -I. -MYAML::XS -MData::Dumper -MMIME::Base64 -d -e "$*"
524    )
525}
526
527## doc: create a bare git clone
528git-bare()
529{
530    ( set +m; _git-bare-bg "$@" )
531}
532
533_git-bare-bg()
534{
535    local url tmpd name
536
537    tmpd=`mktemp -d` || exit 1
538    trap "rm -fr $tmpd" EXIT
539
540    for url; do
541        ## remove /.git
542        name=$(rtrim / "$url")
543        name="${name%.git}"
544        name=$(rtrim / "$name")
545
546        ## remove url, add .git
547        name="${name##*/}.git"
548
549        if [ "$name" = ".git" ]; then
550            echo "coudln't get name for $url"
551            continue
552        fi
553
554        if [ -d "$name" ]; then
555            echo "skipping $name, already exists"
556            continue
557        fi
558        (
559            if { git clone --bare "$url" "$name" &&
560                cd "$name" &&
561                git remote add -f --mirror origin "$url" ||
562                {
563                    git config remote.origin.url "$url" &&
564                    git config remote.origin.fetch "+refs/heads/*:refs/heads/*"
565                }
566            } &> $tmpd/$$; then
567                echo "finished $name"
568            else
569                echo "failed to create $name:"
570                tail -n 3 $tmpd/$$
571            fi
572        ) &
573    done
574    wait
575}
576
577## doc: remove a line from a file: rmline <file> <line> or <file:line>
578rmline()
579{
580    local file line
581
582    file="$1"
583    line="$2"
584
585    if [ -z "$file" ]; then
586        err "missing file to remove"
587        return 1
588    fi
589
590    if [ -z "$line" ]; then
591        line="${file##*:}"
592        file="${file%:*}"
593    fi
594
595    if ! [ -e "$file" ]; then
596        err "file to remove doesn't exist"
597        return 1
598    fi
599
600    if [ -z "$line" ]; then
601        err "missing line to remove"
602        return 1
603    fi
604
605    ed -s "$file" <<-EOF
606        ${line}d
607        wq
608EOF
609}
610
611## doc: show local IP addresses
612ips()
613{
614    (
615        PATH=$PATH:/usr/sbin:/sbin
616        if _exists ip; then
617            ip addr show to 0/0
618        else
619            ifconfig | awk '/^[^ \t]/{i=$1} /inet/{ print i $0}'
620        fi
621    )
622}
623
624## doc: list interfaces belonging to a bridge
625brif()
626{
627    local br="$1"
628    shift
629
630    brctl show | awk -v br=$br '
631        BEGIN { inbr=0 }
632        /^[^ \t]/ { inbr=0 }
633        $1 == br {
634            if ($4) { print $4 }
635            inbr=1
636        }
637        /^[ \t]/ && inbr==1 { print $1 }
638    '
639}
640
641## doc: list content differences between two directories
642dirdiff()
643{
644    local src="$1" dst
645    dst="${2:-.}"
646
647    if [ -z "$src" ]; then
648        err "missing original directory"
649        return 1
650    fi
651
652    if ! [ -d "$src" ]; then
653        err "$src: not a directory"
654        return 1
655    fi
656    if ! [ -d "$dst" ]; then
657        err "$dst: not a directory"
658        return 1
659    fi
660
661    diff -u <(cd "$src" && find . | LC_ALL=C sort | sed -e 's/^..//') \
662        <(cd "$dst" && find . | LC_ALL=C sort | sed -e 's/^..//')
663}
664
665## doc: execute command with path to a binary; path added to the end or where '%' is
666bin()
667{
668    local p a cmd spec
669
670    p=$(type -P "$1" 2>/dev/null)
671    if [ -z "$p" ]; then
672        err "couldn't find $1"
673        return 1
674    fi
675    shift
676
677    if [ $# -eq 0 ]; then
678        echo $p
679        return 0
680    fi
681
682    declare -a cmd
683    spec=
684    for a; do
685        if [ "$a" = "%" ]; then
686            cmd+=("$p")
687            spec=1
688        else
689            cmd+=("$a")
690        fi
691    done
692    [ -z "$spec" ] && cmd+=("$p")
693    eval "${cmd[@]}"
694}
695
696## doc: show nfo
697nfo()
698{
699    local f="$1" a
700
701    if [ -d "$f" ]; then
702        declare -a a
703        a=("$f"/*.[nN][fF][oO])
704        f="$a"
705    fi
706
707    if ! [ -f "$f" ]; then
708        err "couldn't find nfo in $f"
709        return 1
710    fi
711
712    iconv -f cp437 "$f" | tr -d '\r' | sed -e 's/^ *$//' |
713        LESS="${LESS:--}rsS" $PAGER
714}
715
716

Archive Download this file

Branches:
master