dot rc

Sign in or create your account | Project List | Help

dot rc Git Source Tree

Root/rc/bash_functions

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

Archive Download this file

Branches:
master