Root/
| 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 |
| 5 | err() |
| 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 |
| 12 | ltrim() |
| 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 |
| 27 | rtrim() |
| 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 |
| 42 | trim() |
| 43 | { |
| 44 | local c="$1" |
| 45 | shift |
| 46 | ltrim "$c" $(rtrim "$c" $*) |
| 47 | } |
| 48 | |
| 49 | ## doc: start screen |
| 50 | s() |
| 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 |
| 61 | wcat() |
| 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 |
| 96 | pass() |
| 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 |
| 122 | extract() |
| 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 |
| 255 | size_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 |
| 273 | size_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 |
| 297 | size_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 |
| 329 | if type -p cdiff &> /dev/null; then |
| 330 | _use_cdiff() |
| 331 | { |
| 332 | if [ -t 1 ]; then |
| 333 | "$@" | cdiff |
| 334 | else |
| 335 | "$@" |
| 336 | fi |
| 337 | } |
| 338 | else |
| 339 | _use_cdiff() |
| 340 | { |
| 341 | if [ -t 1 ]; then |
| 342 | "$@" | $PAGER |
| 343 | else |
| 344 | "$@" |
| 345 | fi |
| 346 | } |
| 347 | fi |
| 348 | |
| 349 | ## doc: make svn more user-friendly |
| 350 | svn() { _dvcs svn "$@"; } |
| 351 | |
| 352 | ## doc: make hg more user-friendly |
| 353 | hg() { _dvcs hg "$@"; } |
| 354 | |
| 355 | ## doc: make cvs more user-friendly |
| 356 | cvs() { _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 |
| 374 | diff() |
| 375 | { |
| 376 | _use_cdiff "$(type -P diff)" -u "$@" |
| 377 | } |
| 378 | |
| 379 | ## doc: crypt(3) |
| 380 | crypt() |
| 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 |
| 396 | svim() |
| 397 | { |
| 398 | _vim vim "$@" |
| 399 | } |
| 400 | |
| 401 | ## run gvim, open multiple windows for multiple files |
| 402 | mvim() |
| 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 |
| 493 | ldir() |
| 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 |
| 504 | lln() |
| 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 |
| 515 | perl_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 |
| 524 | perldbg() |
| 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 |
| 561 | git-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> |
| 611 | rmline() |
| 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 |
| 641 | EOF |
| 642 | } |
| 643 | |
| 644 | ## doc: show local IP addresses |
| 645 | ips() |
| 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 |
| 658 | brif() |
| 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 |
| 675 | dirdiff() |
| 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 |
| 699 | bin() |
| 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 |
| 730 | nfo() |
| 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 | |
