#!/usr/bin/env bash # # Author: Georg Voell - georg.voell@standby.cloud # Version: @(#)get-ip 3.3.1 16.03.2026 (c)2026 Standby.cloud # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ # # This script can be used free of charge. Use it as is or customize as needed. It is not guaranteed to be # error free and you will not be reimbursed for any damage it may cause. # #@ Get the external ip of the instance and some more infos. #@ #@Usage: get-ip [options] [keys] #@ Options: #@ -h, --help : Displays helptext. #@ -v, --version : Displays the version of the script. #@ -o, --output : Output format: can be "plain" (default), "keys", "json", "etsv", "tsv", "line" or "table". #@ Keys: Optional - Select the keys you want to display. #@ ip : Displays the IP e.g. "87.162.84.113". #@ country: Displays the Country e.g. "Germany". #@ city : Displays the City e.g. "Berlin". #@ asn : Displays the ASN ID e.g. "AS3320" #@ #@Examples: #@ get-ip ip #@ get-ip --output json # # Exit codes: # 01: Unknown or wrong parameter. # 02: **curl** not found. # 03: Key not found # 04: No internet access. # 99: User interrupt. # # Update history: # # V 3.0.0 24.04.2020 New version # V 3.1.0 05.06.2023 New copyright # V 3.2.0 05.09.2024 New minor version # V 3.3.0 19.01.2026 Revised with support of Claude Code # V 3.3.1 16.03.2026 Optimized: replaced backticks with $(); [ ] with [[ ]]; # echo|grep with [[ == *:* ]]; UUOC removed; [ -a ] with && # # Find executable bash library and source it lib=$(command -v lib.bash 2>/dev/null) if [[ -n "$lib" ]]; then source "$lib" else progdir=$(dirname "$0") if [[ -r "${progdir}/lib.bash" ]]; then source "${progdir}/lib.bash" else echo "Unexpected error: Unable to locate bash library 'lib.bash'." exit 1 fi fi # Do extra cleanup function ExtraCleanup() { filecheck -rm "${scratchfile}.pre" } # Set the Base URLs readonly url="https://ifconfig.co" readonly baseurl="https://standby.cloud" readonly asnurl="${baseurl}/cgi-bin/get-asn.pl?param" readonly ipurl="${baseurl}/cgi-bin/ip.pl" # Preset param="" formatstr="" # Check parameters: Loop until all parameters are used up while [[ $# -gt 0 ]]; do pname="${1}" case "$pname" in -o | --output) shift if [[ -n "$1" ]]; then if [[ -z "$formatstr" ]]; then formatstr=$(ToLower "$1") case "$formatstr" in plain|keys|json|etsv|tsv|line|table) ;; *) errstr="Unknown format '$formatstr' after parameter '$pname'. Please choose from 'plain', 'keys', 'json', 'etsv', 'tsv', 'line' or 'table'." ;; esac else errstr="Option '$pname' used more then once." fi shift else errstr="Please specify a format ('plain', 'keys', 'json', 'etsv', 'tsv', 'line' or 'table') after parameter '$pname'." fi ;; -v | --version) shift showversion=true ;; -h | --help) shift showhelp=true ;; *) shift if [[ "$pname" == -* ]]; then errstr="Unknown option '$pname'." else if [[ -z "$param" ]]; then param=$(ToLower "$pname") else errstr="Keys were already specified '$param'. Unknown additional parameter: '$pname'." fi fi ;; esac done # Check if we can reformat the output pt=$(filecheck -x print-table) # Display help or error message DisplayHelp # Set output to plain if not specified if [[ -z "$formatstr" ]]; then formatstr="plain" fi # Check if we have curl in path curl=$(filecheck -x curl) if [[ -z "$curl" ]]; then exitcode=2 errormsg $exitcode "($progstr) No 'curl' in '$PATH'. Please install first e.g. 'sudo yum -y install curl'." exit $exitcode else # Application Error = 3: Redo until we do not get an Application Error stat=3 while [[ $stat -eq 3 ]]; do if [[ "$param" == "ip" || "$param" == "ip_v4" || "$param" == "country" || "$param" == "city" ]]; then printf '%s\n' "$param" > "$scratchfile" # Don't use JSON if we have the above parameter if [[ "$param" == "ip_v4" ]]; then myurl="$ipurl" else myurl="${url}/${param}" fi else myurl="${url}/json" fi # Get result from server via curl transfer --quiet --seconds 15 "$myurl" >> "$scratchfile" stat=$? if [[ $stat -eq 0 ]]; then if [[ "$myurl" == "${url}/json" ]]; then # Get ip from scratch and check if it is an ipv6 myip=$(grep '"ip": ' "$scratchfile" | cut -d'"' -f4) # Use bash pattern match to detect IPv6 (contains ':') if [[ "$myip" != *":"* ]]; then ipv4="$myip" ipv6="//" else ipv6="$myip" ipv4=$(${curl} -4skL --connect-timeout 15 "$url") stat=$? [[ $stat -ne 0 ]] && ipv4="" fi # Parse JSON fields (grep+cut is still the cleanest without jq) ipdec=$(grep ' "ip_decimal": ' "$scratchfile" | cut -d':' -f2 | sed 's|^ ||g' | sed 's|,$||g') country=$(grep ' "country": ' "$scratchfile" | cut -d'"' -f4) countryiso=$(grep ' "country_iso": ' "$scratchfile" | cut -d'"' -f4) countryeu=$(grep ' "country_eu": ' "$scratchfile" | cut -d':' -f2 | sed 's|^ ||g' | sed 's|,$||g') regionname=$(grep ' "region_name": ' "$scratchfile" | cut -d'"' -f4) regioncode=$(grep ' "region_code": ' "$scratchfile" | cut -d'"' -f4) zipcode=$(grep ' "zip_code": ' "$scratchfile" | cut -d'"' -f4) city=$(grep ' "city": ' "$scratchfile" | cut -d'"' -f4) latitude=$(grep ' "latitude": ' "$scratchfile" | cut -d':' -f2 | sed 's|^ ||g' | sed 's|,$||g') longitude=$(grep ' "longitude": ' "$scratchfile" | cut -d':' -f2 | sed 's|^ ||g' | sed 's|,$||g') timezone=$(grep ' "time_zone": ' "$scratchfile" | cut -d'"' -f4) # Determine asn and asn_org asn=$(grep ' "asn": ' "$scratchfile" | cut -d'"' -f4) asnorg=$(grep ' "asn_org": ' "$scratchfile" | cut -d'"' -f4) if [[ -z "$asn" || -z "$asnorg" ]]; then # No asn in response from ifconfig.co - try elsewhere check="${ipv4:-$myip}" if [[ -n "$check" ]]; then transfer --quiet --seconds 15 "${asnurl}=${check}" > "${scratchfile}.pre" stat=$? if [[ $stat -eq 0 ]]; then result=$(grep '\[AS' "${scratchfile}.pre" | taillastline | cut -d'[' -f2) asnorg=$(printf '%s' "$result" | cut -d']' -f2 | cut -d',' -f1) asnorg="${asnorg/ /}" if [[ -z "$asn" ]]; then asn=$(printf '%s' "$result" | cut -d']' -f1) fi fi fi fi # Get last parameters product=$(grep ' "product": ' "$scratchfile" | cut -d'"' -f4) pvers=$(grep ' "version": ' "$scratchfile" | cut -d'"' -f4) rawvalue=$(grep ' "raw_value": ' "$scratchfile" | cut -d'"' -f4) hname=$(grep ' "hostname": ' "$scratchfile" | cut -d'"' -f4) [[ -z "$hname" ]] && hname="//" # Create tsv file printf "ip\tip_v4\tip_v6\tip_decimal\tcountry\tcountry_iso\tcountry_eu\tregion_name\tregion_code\tzip_code\tcity\tlatitude\tlongitude\ttime_zone\tasn\tasn_org\thostname\tuser_agent/product\tuser_agent/version\tuser_agent/raw_value\n" > "$scratchfile" printf "%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\n" \ "$myip" "$ipv4" "$ipv6" "/${ipdec}/" "$country" "$countryiso" "/${countryeu}/" \ "$regionname" "$regioncode" "$zipcode" "$city" "/${latitude}/" \ "/${longitude}/" "$timezone" "$asn" "$asnorg" "$hname" "$product" "$pvers" "$rawvalue" >> "$scratchfile" fi # Display the result if [[ -z "$param" ]]; then if [[ -z "$pt" ]]; then cat "$scratchfile" else cat "$scratchfile" | $pt --quiet --output "$formatstr" > "${scratchfile}.pre" fi else if [[ "$myurl" == "${url}/json" ]]; then cat "$scratchfile" | $pt --quiet --output "$formatstr" "$param" > "${scratchfile}.pre" stat=$? if [[ $stat -ne 0 ]]; then exitcode=3 errormsg $exitcode "($progstr) None of the specified keys were found. Exiting." Cleanup exit $exitcode fi else if [[ "$formatstr" == "plain" ]]; then taillastline "$scratchfile" Cleanup exit else cat "$scratchfile" | $pt --quiet --output "$formatstr" > "${scratchfile}.pre" fi fi fi if [[ "$ENVELOPE_TABLE" == false || "$formatstr" != "json" ]]; then cat "${scratchfile}.pre" else cat "${scratchfile}.pre" | sed 's|\("contentItems":.*\)|\1,\n "creator": "'"$progstr"'"|' fi else if [[ $stat -ne 3 ]]; then exitcode=4 Cleanup exit $exitcode fi fi done fi # Cleanup and exit Cleanup exit $exitcode