From 8bfab5e17539b37f1d21584da19e79f8751d6846 Mon Sep 17 00:00:00 2001 From: Honza Hommer Date: Sun, 15 Mar 2020 19:10:34 +0100 Subject: [PATCH] Batman! (this commit has no parents) --- .travis.yml | 9 +++ LICENSE | 21 +++++++ README.md | 56 +++++++++++++++++ bin/prips.sh | 1 + install.sh | 26 ++++++++ libexec/prips.sh | 153 +++++++++++++++++++++++++++++++++++++++++++++++ test/prips.bats | 122 +++++++++++++++++++++++++++++++++++++ 7 files changed, 388 insertions(+) create mode 100644 .travis.yml create mode 100644 LICENSE create mode 100644 README.md create mode 120000 bin/prips.sh create mode 100755 install.sh create mode 100755 libexec/prips.sh create mode 100755 test/prips.bats diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..540cb7a --- /dev/null +++ b/.travis.yml @@ -0,0 +1,9 @@ +language: shell +sudo: required +before_install: + - sudo add-apt-repository ppa:duggan/bats --yes + - sudo apt-get update -qq + - sudo apt-get install -qq bats +script: + - bash -c 'shopt -s globstar nullglob; shellcheck **/*.sh' + - bats test/*.bats diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..3ed5e84 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2020 Honza Hommer + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..67844a1 --- /dev/null +++ b/README.md @@ -0,0 +1,56 @@ +# prips.sh + +[![build status](https://img.shields.io/travis/honzahommer/prips.sh/master.svg)](http://travis-ci.org/honzahommer/prips.sh) + +> Print the IP addresses in a given range + +## Usage + +Invoking `prips.sh -h` prints usage information: + + $ prips.sh -h + $ usage: prips.sh [options] + $ -n set the number of addresses to print ( must not be set) + $ -f set the format of addresses (hex, dec, or dot) + $ -i set the increment to 'x' + $ -h display this help message and exit + $ -v display the version number and exit + +Display all the addresses in a reserved subnet: + + $ prips.sh 192.168.0.0 192.168.0.255 + +Display every fourth address in a weird block: + + $ prips.sh -i4 192.168.0.10 192.168.0.250 + +## Installing prips.sh from source + +Check out a copy of the prips.sh repository. Then, either add the prips.sh +`bin` directory to your `$PATH`, or run the provided `install.sh` command +with the location to the prefix in which you want to install prips.sh. +For example, to install prips.sh into `/usr/local`: + + $ git clone https://github.com/honzahommer/prips.sh.git + $ cd prips.sh + $ ./install.sh /usr/local + +Note that you may need to run `install.sh` with `sudo` if you do not +have permission to write to the installation prefix. + +## Support + +The prips.sh source code repository is [hosted on +GitHub](https://github.com/honzahommer/prips.sh). There you can file bugs +on the issue tracker or submit tested pull requests for review. + +## Version history + +*0.1.0* (March 15, 2020) + +* Initial public release. + +--- + +© 2020 Honza Hommer. prips.sh is released under an MIT-style license; +see `LICENSE` for details. diff --git a/bin/prips.sh b/bin/prips.sh new file mode 120000 index 0000000..e00543c --- /dev/null +++ b/bin/prips.sh @@ -0,0 +1 @@ +../libexec/prips.sh \ No newline at end of file diff --git a/install.sh b/install.sh new file mode 100755 index 0000000..78b1c09 --- /dev/null +++ b/install.sh @@ -0,0 +1,26 @@ +#!/usr/bin/env bash +set -e + +__dirname() { + local s="${1:-$0}" + local d + + while [ -h "$s" ]; do + d="$(cd -P "$(dirname "$s")" >/dev/null 2>&1 && pwd)" + s="$(readlink "$s" 2>&1)" + + [[ $s != /* ]] && s="$d/$s" + done + + cd -P "$(dirname "$s")" >/dev/null 2>&1 && pwd +} + +readonly PRIPS_PREFIX="${1:-$PREFIX}" +readonly PRIPS_ROOT="$(__dirname "$0")" + +mkdir -p "$PRIPS_PREFIX"/{bin,libexec} + +cp -R "$PRIPS_ROOT"/bin/* "$PRIPS_PREFIX"/bin +cp -R "$PRIPS_ROOT"/libexec/* "$PRIPS_PREFIX"/libexec + +echo "Installed prips.sh to $PREFIX/bin/prips.sh" diff --git a/libexec/prips.sh b/libexec/prips.sh new file mode 100755 index 0000000..e683fc9 --- /dev/null +++ b/libexec/prips.sh @@ -0,0 +1,153 @@ +#!/usr/bin/env bash +set -e + +prips() { + prips:help() { + cat << EOF 1>&2 +usage: $_this [options] + -n set the number of addresses to print ( must not be set) + -f set the format of addresses (hex, dec, or dot) + -i set the increment to 'x' + -h display this help message and exit + -v display the version number and exit +EOF + exit 1 + } + + prips:error() { + local code=1 + + case ${1} in + -[0-9]*) + code=${1#-} + shift + ;; + esac + + echo "$_this: $*" 1>&2 + exit "$code" + } + + prips:aton() { + local ip=$1 + local ipnum=0 + + for (( i=0; i<4; ++i )); do + ((ipnum+=${ip%%.*}*$((256**$((3-i)))))) + ip=${ip#*.} + done + + echo $ipnum + } + + prips:ntoa() { + echo -n $(($(($(($((${1}/256))/256))/256))%256)). + echo -n $(($(($((${1}/256))/256))%256)). + echo -n $(($((${1}/256))%256)). + echo $((${1}%256)) + } + + prips:isint() { + (( $1 > 0 )) 2>/dev/null + } + + prips:isip() { + [[ $1 =~ ^[0-9]+(\.[0-9]+){3}$ ]] + } + + prips:set() { + local var=$1 + local val=${2:-$3} + + case ${var} in + f) + var="format" + + ! echo "${_formats[@]}" | grep -qw "$val" && \ + prips:error "invalid format '$val'" + ;; + i) + var="increment" + + ! prips:isint "$val" && \ + prips:error "$var must be a positive integer" + ;; + n) + var="count" + + ! prips:isint "$val" && \ + prips:error "$var must be a positive integer" + + args=1 + ;; + t) + var="_this" + ;; + start | end) + prips:isip "$val" && \ + val=$(prips:aton "$val") + + ! prips:isint "$val" && \ + prips:error "bad IP address" + ;; + esac + + eval "$var=\"$val\"" + } + + local _formats=("dec" "dot" "hex") + local _this="prips" + local _version="0.1.0" + + local args=2 + local count=0 + local increment=1 + local format="dot" + local start + local end + + while getopts "f:i:n:t:?hv" opt; do + case ${opt} in + f | i | n | t) + prips:set "$opt" "$OPTARG" + ;; + v) + prips:error -0 "v$_version" + ;; + h | \? | :) + prips:help + ;; + esac + done + shift $((OPTIND -1)) + + if [ $# -ne $args ]; then + prips:help + fi + + prips:set start "$1" + prips:set end "$2" "$(( start + (increment * count) - 1 ))" + + [[ $end -lt $start ]] && \ + prips:error "start address must be smaller than end address" + + while [[ $start -le $end ]]; do + case ${format} in + dec) + echo "$start" + ;; + hex) + printf '%X\n' "$start" + ;; + *) + prips:ntoa "$start" + ;; + esac + + start=$(( start + increment )) + done +} + +if [[ "${BASH_SOURCE[0]}" = "${0}" ]]; then + prips -t "$(basename "$0")" "$@" +fi diff --git a/test/prips.bats b/test/prips.bats new file mode 100755 index 0000000..796467d --- /dev/null +++ b/test/prips.bats @@ -0,0 +1,122 @@ +#!/usr/bin/env bats + +@test "prips.sh" { + run $BATS_TEST_DIRNAME/../bin/prips.sh + [ "$status" -eq 1 ] + [ "${lines[0]}" = "usage: prips.sh [options] " ] +} + +@test "prips.sh -h" { + run $BATS_TEST_DIRNAME/../bin/prips.sh -h + [ "$status" -eq 1 ] + [ "${lines[0]}" = "usage: prips.sh [options] " ] +} + +@test "prips.sh -v" { + run $BATS_TEST_DIRNAME/../bin/prips.sh -v + [ "$status" -eq 0 ] + [ "${lines[0]}" = "prips.sh: v0.1.0" ] +} + +@test "prips.sh -n0" { + run $BATS_TEST_DIRNAME/../bin/prips.sh -n0 + [ "$status" -eq 1 ] + [ "${lines[0]}" = "prips.sh: count must be a positive integer" ] +} + +@test "prips.sh -n11 192.168.0.0 192.168.0.10" { + run $BATS_TEST_DIRNAME/../bin/prips.sh -n11 192.168.0.0 192.168.0.10 + [ "$status" -eq 1 ] + [ "${lines[0]}" = "usage: prips.sh [options] " ] +} + +@test "prips.sh -i0" { + run $BATS_TEST_DIRNAME/../bin/prips.sh -i0 + [ "$status" -eq 1 ] + [ "${lines[0]}" = "prips.sh: increment must be a positive integer" ] +} + +@test "prips.sh -fx" { + run $BATS_TEST_DIRNAME/../bin/prips.sh -fx + [ "$status" -eq 1 ] + [ "${lines[0]}" = "prips.sh: invalid format 'x'" ] +} + +@test "prips.sh 192.168.0.0" { + run $BATS_TEST_DIRNAME/../bin/prips.sh 192.168.0.0 + [ "$status" -eq 1 ] + [ "${lines[0]}" = "usage: prips.sh [options] " ] +} + +@test "prips.sh 192.168.0.x 192.168.0.10" { + run $BATS_TEST_DIRNAME/../bin/prips.sh 192.168.0.x 192.168.0.10 + [ "$status" -eq 1 ] + [ "${lines[0]}" = "prips.sh: bad IP address" ] +} + +@test "prips.sh 192.168.0.0 192.168.0.x" { + run $BATS_TEST_DIRNAME/../bin/prips.sh 192.168.0.0 192.168.0.x + [ "$status" -eq 1 ] + [ "${lines[0]}" = "prips.sh: bad IP address" ] +} + +@test "prips.sh 192.168.0.x 192.168.0.x" { + run $BATS_TEST_DIRNAME/../bin/prips.sh 192.168.0.x 192.168.0.x + [ "$status" -eq 1 ] + [ "${lines[0]}" = "prips.sh: bad IP address" ] +} + +@test "prips.sh 192.168.0.10 192.168.0.0" { + run $BATS_TEST_DIRNAME/../bin/prips.sh 192.168.0.10 192.168.0.0 + [ "$status" -eq 1 ] + [ "${lines[0]}" = "prips.sh: start address must be smaller than end address" ] +} + +@test "prips.sh 192.168.0.0 192.168.0.10" { + run $BATS_TEST_DIRNAME/../bin/prips.sh 192.168.0.0 192.168.0.10 + [ "$status" -eq 0 ] + [ "${lines[0]}" = "192.168.0.0" ] + [ "${lines[10]}" = "192.168.0.10" ] +} + +@test "prips.sh -i2 192.168.0.0 192.168.0.10" { + run $BATS_TEST_DIRNAME/../bin/prips.sh -i2 192.168.0.0 192.168.0.10 + [ "$status" -eq 0 ] + [ "${lines[0]}" = "192.168.0.0" ] + [ "${lines[5]}" = "192.168.0.10" ] +} + +@test "prips.sh -n11 192.168.0.0" { + run $BATS_TEST_DIRNAME/../bin/prips.sh -n11 192.168.0.0 + [ "$status" -eq 0 ] + [ "${lines[0]}" = "192.168.0.0" ] + [ "${lines[10]}" = "192.168.0.10" ] +} + +@test "prips.sh -i2 -n11 192.168.0.0" { + run $BATS_TEST_DIRNAME/../bin/prips.sh -i2 -n11 192.168.0.0 + [ "$status" -eq 0 ] + [ "${lines[0]}" = "192.168.0.0" ] + [ "${lines[10]}" = "192.168.0.20" ] +} + +@test "prips.sh -fdot 192.168.0.0 192.168.0.10" { + run $BATS_TEST_DIRNAME/../bin/prips.sh -fdot 192.168.0.0 192.168.0.10 + [ "$status" -eq 0 ] + [ "${lines[0]}" = "192.168.0.0" ] + [ "${lines[10]}" = "192.168.0.10" ] +} + +@test "prips.sh -fdec 192.168.0.0 192.168.0.10" { + run $BATS_TEST_DIRNAME/../bin/prips.sh -fdec 192.168.0.0 192.168.0.10 + [ "$status" -eq 0 ] + [ "${lines[0]}" = "3232235520" ] + [ "${lines[10]}" = "3232235530" ] +} + +@test "prips.sh -fhex 192.168.0.0 192.168.0.10" { + run $BATS_TEST_DIRNAME/../bin/prips.sh -fhex 192.168.0.0 192.168.0.10 + [ "$status" -eq 0 ] + [ "${lines[0]}" = "C0A80000" ] + [ "${lines[10]}" = "C0A8000A" ] +}