#!/usr/bin/env bash # # Author: Georg Voell - georg.voell@standby.cloud # Version: @(#)transfer 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 a resource from a host (or internet) via curl and check if an error occured. #@ #@Usage: transfer [options] url #@ Options: #@ -h, --help : Displays helptext. #@ -v, --version : Displays the version of the script. #@ -q, --quiet : Don't display any error messages. #@ -a, --auth : Using Oracle Authorization Header e.g. -H "Authorization: Bearer Oracle". #@ -s, --seconds : Max of seconds for the operation to take (default is 10). #@ -i, --import : Read from a file and upload it. #@ -e, --export : Write output to file "". #@ URL: URL can be specified with or without leading "http://". #@ #@Examples: #@ transfer http://standby.cloud/download/pdf/Basic-Admin-Scripts.pdf --export manual.pdf #@ Downloads manual.pdf from server. #@ transfer --auth http://169.254.169.254/opc/v2/instance #@ Downloads oci instance metadata for current VM. # # Exit codes: # 01: Unknown or wrong parameter. # 02: **curl** not found. This script needs **curl** to perform. # 03: Application error. # 04: HTML error. # 05: JSON error or ObjectNotFound # 06: No internet connection or URL not found. # 07: Uptload to URL failed. # 99: User interrupt. # # Update history: # # V 3.0.0 24.04.2020 New version # V 3.0.1 02.06.2020 Updated documentation # V 3.0.2 11.06.2020 Using library # V 3.0.3 17.09.2020 Using --connect-timeout instead of --max-time # V 3.0.4 16.01.2021 Introduce Oracle Authorization Header # V 3.0.5 13.03.2021 Check if we could write to output file # V 3.1.0 05.06.2023 New copyright # V 3.2.0 11.09.2024 New minor version # V 3.2.1 10.10.2024 Small bug fix # V 3.2.2 12.08.2025 Check if download from Objectstorage failed # V 3.2.3 12.08.2025 New option "-i" import from file and upload it # 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 [[ == pattern ]]; UUOC removed; # replaced [ -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 # We expect messages in english SAVEDLANG="$LANG" LANG="en_US.UTF-8" # Do extra cleanup function ExtraCleanup() { filecheck -rm "${scratchfile}.log" LANG="$SAVEDLANG" } # Preset param="" outfile="" infile="" quietstr="" useauth=false debug=false seconds=5 # Check parameters: Loop until all parameters are used up while [[ $# -gt 0 ]]; do pname="${1}" case "$pname" in -s | --seconds) shift if [[ -n "$1" ]]; then seconds="${1}" shift else errstr="Please specify max number of seconds for the operation to take after '$pname'." fi ;; -i | --import) shift if [[ -n "$outfile" ]]; then errstr="Unable to import and export at the same time." else if [[ -n "$1" ]]; then if [[ -z "$infile" ]]; then infile="$1" if [[ ! -r "$infile" ]]; then errstr="Can't read from filename '$infile'." fi else errstr="Option '$pname' used more then once." fi shift else errstr="Please specify a filename after parameter '$pname'." fi fi ;; -e | --export) shift if [[ -n "$infile" ]]; then errstr="Unable to import and export at the same time." else if [[ -n "$1" ]]; then if [[ -z "$outfile" ]]; then outfile="${1}" result=$(filecheck -w "$outfile") if [[ -z "$result" ]]; then errstr="Filename '$outfile' not writable." fi else errstr="Option '$pname' used more then once." fi shift else errstr="Please specify a filename after '$pname'." fi fi ;; -a | --auth) shift useauth=true ;; -v | --version) shift showversion=true ;; -h | --help) shift showhelp=true ;; -q | --quiet) shift quietstr="$pname" ;; -d | --debug) shift debug=true ;; *) shift if [[ "$pname" == -* ]]; then errstr="Unknown option '$pname'." else if [[ -z "$param" ]]; then param="$pname" else errstr="URL was already specified '$param'. Unknown additional parameter: '$pname'." fi fi ;; esac done # Plausibility check if [[ -z "$param" ]]; then errstr="No hostname or URL specified." fi # Display help or error message DisplayHelp # curlparam can only be set after parameter evaluation: Need $seconds curlparam="-skL --connect-timeout ${seconds}" # Check if we have curl (and optionally jq) in path curl=$(filecheck -x curl) jq=$(filecheck -x jq) if [[ -z "$curl" ]]; then exitcode=2 errormsg $exitcode "($progstr) No 'curl' in '$PATH'. Please install first e.g. 'sudo yum -y install curl'." else if [[ -n "$infile" ]]; then # Upload file to URL $curl $curlparam -T "$infile" "$param" 2> "${scratchfile}.log" stat=$? if [[ $stat -ne 0 ]]; then exitcode=7 errormsg $exitcode "($progstr) Upload to URL '$param' failed." fi else # Get result from URL via curl if [[ "$useauth" == false ]]; then $curl $curlparam "$param" -o "$scratchfile" 2> "${scratchfile}.log" stat=$? else $curl $curlparam -H "Authorization: Bearer Oracle" "$param" -o "$scratchfile" 2> "${scratchfile}.log" stat=$? fi if [[ $stat -eq 0 && -f "$scratchfile" ]]; then result=$(filecheck -b "$scratchfile") if [[ -z "$result" ]]; then # scratchfile is not a binary file - check it for errors if [[ "$debug" == true ]]; then printf 'Have result.\n' >> "${scratchfile}.log"; fi firstline=$(head -n 1 "$scratchfile") if [[ "$firstline" == "<"* ]]; then # HTML response if [[ "$debug" == true ]]; then printf "Found html: '%s'.\n" "$firstline" >> "${scratchfile}.log"; fi grepres=$(grep '>Application Error' "$scratchfile") if [[ -n "$grepres" ]]; then grepres=$(printf '%s' "$grepres" | cut -d'>' -f2 | cut -d'<' -f1) if [[ "$debug" == true ]]; then printf "result: '%s'.\n" "$grepres" >> "${scratchfile}.log"; fi printf "" > "$scratchfile" exitcode=3 errormsg $quietstr $exitcode "($progstr) ${grepres}." "URL: $param" else grepres=$(grep '>Error' "$scratchfile") if [[ -n "$grepres" ]]; then result=$(printf '%s' "$grepres" | awk -F '>Error ' '{print $NF}' | cut -d'<' -f1) if [[ "$debug" == true ]]; then printf "result: 'Error %s'.\n" "$result" >> "${scratchfile}.log"; fi printf "" > "$scratchfile" exitcode=4 errormsg $quietstr $exitcode "($progstr) HTML Error." "$result" else grepres=$(grep '>300 Multiple Choices<' "$scratchfile") if [[ -n "$grepres" ]]; then if [[ "$debug" == true ]]; then printf "result: '300 Multiple Choices'.\n" >> "${scratchfile}.log"; fi printf "" > "$scratchfile" exitcode=4 errormsg $quietstr $exitcode "($progstr) HTML Error." "300 Multiple Choices" fi fi fi elif [[ "$firstline" == "{"* ]]; then # JSON response if [[ "$debug" == true ]]; then printf 'Found json.\n' >> "${scratchfile}.log"; fi if [[ -n "$jq" ]]; then # jq is installed - pretty print and validate JSON # Avoid UUOC: redirect file directly "$jq" '.' < "$scratchfile" > "${scratchfile}.out" 2>&1 stat=$? if [[ $stat -gt 0 ]]; then exitcode=5 result=$(cat "${scratchfile}.out") if [[ "$debug" == true ]]; then printf "jq detected an error in JSON: %s\n" "$result" >> "${scratchfile}.log"; fi filecheck -rm "${scratchfile}.out" printf "" > "$scratchfile" errormsg $quietstr $exitcode "($progstr) JSON Error." "$result" else # Check if downloaded from Objectstorage and file was not found grepres=$(tailfromline2 "${scratchfile}.out" | head -n 1 | grep '"code": "' | cut -d'"' -f4) if [[ -n "$grepres" ]]; then exitcode=5 printf "" > "$scratchfile" result=$(basename "$param") errormsg $quietstr $exitcode "($progstr) JSON code: '$grepres'." "$result" else mv "${scratchfile}.out" "$scratchfile" fi fi fi fi # Check for 404 (plain text, not HTML) firstline=$(head -n 1 "$scratchfile") if [[ "$firstline" == "404 page not found"* ]]; then if [[ "$debug" == true ]]; then printf "result: 'Error %s'.\n" "$firstline" >> "${scratchfile}.log"; fi printf "" > "$scratchfile" exitcode=4 errormsg $quietstr $exitcode "($progstr) HTML Error." "404 page not found" fi fi else # No internet access or URL not found if [[ "$debug" == true ]]; then printf "No internet access or URL '%s' not found.\n" "$param" >> "${scratchfile}.log" printf "stat: '%s'.\n" "$stat" >> "${scratchfile}.log" fi exitcode=6 errormsg $quietstr $exitcode "($progstr) No internet access or URL '$param' not found." fi if [[ "$debug" == true ]]; then printf 'Logfile:\n' >/dev/stderr cat "${scratchfile}.log" >/dev/stderr printf 'End of Logfile.\n' >/dev/stderr fi # If we got a result, print or save it result=$(filecheck -s "$scratchfile") if [[ -n "$result" ]]; then if [[ -n "$outfile" ]]; then cat "$scratchfile" > "$outfile" else cat "$scratchfile" fi fi fi fi # Cleanup and exit Cleanup exit $exitcode