#!/usr/bin/env bash # # Author: Georg Voell - georg.voell@standby.cloud # Version: @(#)filecheck 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. # #@ Do some actions with files. #@ #@Usage: filecheck [options] filename #@ Options: #@ -h, --help : Displays helptext. #@ -v, --version: Displays the version of the script. #@ -x : Test if filename is executable. If filename can't be found, try to find it in path. #@ -b : Test if filename is a binary file. #@ -f : Test if filename exists and is a regulary file. #@ -l : Test if filename exists and is a symbolic link. #@ -w : Test if filename is writable. #@ -d : Test if filename is a directory. #@ -z : Test if filename is a zip file and not corrupt. #@ -s : Test if filename exists and is not empty. #@ -sl : Test if filename exists and has more than 1 line. #@ -rm : Test if filename exists and then remove it. #@ -fc : Test if filename was accessed no longer than 179 minutes ago (ca. 3 hours). #@ -fy : Test if filename was created no longer than 1339 minutes ago (ca. 1 day). #@ -fw : Test if filename was created no longer than 10079 minutes ago (ca. 1 week). #@ -fmax : Test if filename was modified no longer than 29 minutes ago. #@ -fmin : Test if filename was modified no longer than 15 minutes ago. #@ -html : Test if filename is valid html. #@ -json : Test if filename is valid json. #@ Filename: Name of file to test. #@ #@Examples: #@ curl=`filecheck -x curl` #@ if [ "$curl" != "" ]; then #@ echo "$curl" #@ fi #@ Will display the fullpath to "curl" if it is found. # # Update history: # # V 1.0.0 26.10.2017 New version # V 1.0.1 15.07.2018 More options # V 2.0.0 09.07.2019 Also look for executable files in $HOME/bin # V 3.0.0 27.04.2020 Renamed script from filetest to filecheck (filetest is a build in cmd) # V 3.0.1 19.05.2020 Return "./$file" if $file is in local dir # V 3.0.2 11.06.2020 Using library # V 3.1.0 05.06.2023 New copyright # V 3.1.1 07.09.2023 Check if alias exists with option -x # V 3.1.2 27.07.2024 Additional options # V 3.2.0 11.09.2024 New minor version # V 3.2.1 10.10.2024 More options # V 3.3.0 19.01.2026 Revised with support of Claude Code # V 3.3.1 16.03.2026 Optimized: removed UUOC (cat|wc -> wc /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 # Returns true if file is regular file and not empty # Note: -s test is not reliable on all Solaris versions, so we use wc function FileNotEmpty() { local filename="${1}" if [[ -f "$filename" ]]; then # Avoid UUOC: redirect file directly into wc (no cat subshell) local bytes bytes=$(wc -c < "$filename") if (( bytes > 0 )); then printf 'true\n' return fi fi printf 'false\n' } # Return number of lines in file function CountLines() { local filename="${1}" local lines=0 if [[ -f "$filename" ]]; then # Avoid UUOC: redirect file directly into wc lines=$(wc -l < "$filename") fi printf '%s\n' "$lines" } # Preset filnam="" option="" # Check parameters: Loop until all parameters are used up while [[ $# -gt 0 ]]; do pname="${1}" case "$pname" in -v | --version) shift showversion=true ;; -h | --help) shift showhelp=true ;; *) shift # Use bash pattern match instead of echo|grep subshell if [[ "$pname" == -* ]]; then if [[ -z "$option" ]]; then option="${pname,,}" # bash built-in lowercase else errstr="Option '$option' already specified. Unknown additional option '$pname'." fi else if [[ -z "$filnam" ]]; then filnam="$pname" else errstr="Filename '$filnam' already specified. Unknown additional parameter: '$pname'." fi fi ;; esac done # Plausibility check if [[ -z "$option" || -z "$filnam" ]]; then errstr="Please specify an option and a filename e.g. '$progstr -x yum'" fi # Display help or error message DisplayHelp case "$option" in -x) # Check alias first result=$(alias 2>/dev/null | grep "alias ${filnam}=" | cut -d"'" -f2 | cut -d" " -f1) if [[ -n "$result" ]]; then filnam="$result" fi if [[ -f "$filnam" && -x "$filnam" ]]; then # It is a file - check if it is in the current directory dname=$(dirname "$filnam") if [[ "$dname" == "." ]]; then printf '%s/%s\n' "$(pwd)" "$(basename "$filnam")" else printf '%s\n' "$filnam" fi else # '2>/dev/null' needed for Linux, sed needed for Solaris 10 resstr=$(which "$filnam" 2>/dev/null | sed "s|^no ${filnam} in .*||") if [[ -n "$resstr" ]]; then printf '%s\n' "$resstr" fi fi ;; -f) if [[ -f "$filnam" ]]; then printf '%s\n' "$filnam" fi ;; -l) if [[ -L "$filnam" ]]; then printf '%s\n' "$filnam" fi ;; -w) if [[ ! -d "$filnam" ]]; then dname=$(dirname "$filnam") if [[ -n "$dname" && ! -d "$dname" ]]; then mkdir -m 0755 -p "$dname" exitcode=$? fi local_remove="true" if [[ -f "$filnam" ]]; then # Don't remove file if it already existed local_remove="false" fi touch "$filnam" 2>/dev/null exitcode=$? if [[ $exitcode -eq 0 ]]; then printf '%s\n' "$filnam" fi if [[ "$local_remove" == "true" ]]; then rm -f "$filnam" 2>/dev/null exitcode=$? fi fi ;; -b) if [[ "$(FileNotEmpty "$filnam")" == "true" ]]; then file=$(which file 2>/dev/null | sed "s|^no ${filnam} in .*||") if [[ -n "$file" ]]; then resstr=$("$file" -b --mime-encoding "$filnam") else resstr=$(grep '' "$filnam" | cut -d' ' -f1 | ToLower) fi if [[ "$resstr" == "binary" ]]; then printf '%s\n' "$filnam" fi fi ;; -d) if [[ -d "$filnam" ]]; then printf '%s\n' "$filnam" fi ;; -z) if [[ "$(FileNotEmpty "$filnam")" == "true" ]]; then unzip=$(which unzip 2>/dev/null | sed "s|^no ${filnam} in .*||") if [[ -n "$unzip" ]]; then $unzip -t "$filnam" >/dev/null 2>&1 stat=$? if [[ $stat -eq 0 ]]; then printf '%s\n' "$filnam" fi fi fi ;; -s) if [[ "$(FileNotEmpty "$filnam")" == "true" ]]; then printf '%s\n' "$filnam" fi ;; -sl) if (( $(CountLines "$filnam") > 1 )); then printf '%s\n' "$filnam" fi ;; -rm) if [[ -f "$filnam" ]]; then rm -f "$filnam" 2>/dev/null exitcode=$? fi ;; # amin = access time, mmin = modification time, cmin = change time, Bmin = creation time (inode) # Get infos about the file with: stat $filnam -fc) minutes=179 if [[ "$OS" == "Darwin" ]]; then resstr=$(find "$filnam" -type f -Bmin -${minutes} 2>/dev/null) else # assuming that noatime is set for disk -> then we get creation date in atime resstr=$(find "$filnam" -type f -amin -${minutes} 2>/dev/null) fi if [[ -n "$resstr" ]]; then printf '%s\n' "$filnam" fi ;; -fy | -fw) if [[ "$option" == "-fy" ]]; then minutes=1339 else minutes=10079 fi resstr=$(find "$filnam" -type f -cmin -${minutes} 2>/dev/null) if [[ -n "$resstr" ]]; then printf '%s\n' "$filnam" fi ;; -fmin | -fmax) if [[ "$option" == "-fmin" ]]; then minutes=15 else minutes=29 fi resstr=$(find "$filnam" -type f -mmin -${minutes} 2>/dev/null) if [[ -n "$resstr" ]]; then printf '%s\n' "$filnam" fi ;; -html) if [[ "$(FileNotEmpty "$filnam")" == "true" ]]; then file=$(which file 2>/dev/null | sed "s|^no ${filnam} in .*||") if [[ -n "$file" ]]; then resstr=$("$file" -b --mime-type "$filnam") if [[ "$resstr" == "text/html" ]]; then printf '%s\n' "$filnam" fi fi fi ;; -json) if [[ "$(FileNotEmpty "$filnam")" == "true" ]]; then jq=$(which jq 2>/dev/null | sed "s|^no ${filnam} in .*||") if [[ -n "$jq" ]]; then # Avoid UUOC: redirect directly "$jq" . < "$filnam" >/dev/null 2>&1 stat=$? if [[ $stat -eq 0 ]]; then printf '%s\n' "$filnam" fi fi fi ;; *) errormsg 1 "($progstr) Invalid option '$option'." exitcode=1 ;; esac exit $exitcode