binsearch: Supports -q and -2.

This commit is contained in:
Ole Tange 2020-08-16 22:18:09 +02:00
parent 4206374f37
commit b29b851281
2 changed files with 79 additions and 21 deletions

View file

@ -19,16 +19,57 @@ B<binsearch> runs I<command> with a single number. It returns highest
value that I<command> succeeds for. value that I<command> succeeds for.
=head1 OPTIONS
=over 4
=item B<-2>
Instead of the command a single argument, give the command 2 argument:
I<from> I<to>.
=item B<-q>
Quiet. Ignore output from B<command>.
=back
=head1 EXAMPLES =head1 EXAMPLES
=head2 Find the last file
This is a silly way to find the last non-existing file (namely 244):
touch {245..800}
binsearch ls
This is a silly way to find the last file (namely 800):
touch {1..800}
binsearch ls
=head2 Test a bash function =head2 Test a bash function
Test how long an argument /bin/echo can take
. $(which binsearch) . $(which binsearch)
singleecho() { singleecho() {
/bin/echo $(perl -e 'print "x"x'$1) >/dev/null /bin/echo $(perl -e 'print "x"x'$1) >/dev/null
} }
binsearch singleecho binsearch singleecho
=head2 Test a bash function that takes from and to as arguments
Use a function that takes two arguments
. $(which binsearch)
greplines() {
env | perl -ne "$1..$2 and print" | grep HOME=
}
binsearch -2 -q greplines
=head1 AUTHOR =head1 AUTHOR
@ -60,19 +101,6 @@ B<eval>(1)
=cut =cut
# Example: find the max line length
#
# singleecho() {
# /bin/echo $(perl -e 'print "x"x'$1) >/dev/null
# }
#
# multiecho() {
# /bin/echo $(perl -e 'print "x "x'$(($1/2)) ) >/dev/null
# }
#
# binsearch singleecho
binsearch() { binsearch() {
_binsearch() { _binsearch() {
low=$1 low=$1
@ -84,7 +112,7 @@ binsearch() {
shift shift
shift shift
middle=$(( ( $low + $high ) / 2 )) middle=$(( ( $low + $high ) / 2 ))
if eval "$@ $middle" ; then if _run $low $middle "$@" ; then
low=$middle low=$middle
else else
high=$middle high=$middle
@ -92,9 +120,35 @@ binsearch() {
_binsearch $low $high "$@" _binsearch $low $high "$@"
} }
low=1 _run() {
local a="$1"
local b="$2"
shift
shift
# echo "a=$a b=$b $@"
if $opt2 ; then
eval "$not" "$@ $a $b" "$quiet"
else
eval "$not" "$@ $b" "$quiet"
fi
}
quiet=""
opt2=false
args=$(getopt 'q2' $*) || exit
# now we have the sanitized args... replace the original with it
set -- $args
while true; do
case $1 in
(-2) opt2=true; shift;;
(-q) quiet=">/dev/null 2>/dev/null"; shift;;
(--) shift; break;;
esac
done
# If function(1) = false: run 'not function()' instead # If function(1) = false: run 'not function()' instead
if eval "$@ $low" ; then if _run 1 1 "$@" ; then
not='' not=''
else else
not='!' not='!'
@ -102,17 +156,21 @@ binsearch() {
# exponential search for the first value that is false # exponential search for the first value that is false
# low = previous value (function($low) == true) # low = previous value (function($low) == true)
# high = low * 2 (function($high) == false) # high = low * 2 (function($high) == false)
high=$low high=1
while eval "$not" "$@ $high" 2>/dev/null ; do while _run 1 $high "$@" ; do
low=$high low=$high
high=$(( $high*2 )) high=$(( $high*2 ))
if [ $high -gt 4611686018427387900 ] ; then
echo "$0: Error: exit value does not change of '$@'" >&2
return
fi
done done
# echo "low: $low high: $high not: $not" # echo "low: $low high: $high not: $not"
_binsearch $low $high "$not $@" 2>/dev/null _binsearch $low $high "$@" 2>/dev/null
echo $low echo $low
} }
if [ -z "$@" ] ; then if [ -z "$*" ] ; then
# source the bash function # source the bash function
# . $(which binsearch) # . $(which binsearch)
true true

View file

@ -9,7 +9,7 @@ splitvideo - Split video at time stamp
=head1 SYNOPSIS =head1 SYNOPSIS
B<splitvideo> time videofile B<splitvideo> I<time> I<videofile>
=head1 DESCRIPTION =head1 DESCRIPTION